KLU Integration from scratch

This commit is contained in:
Francesco Lannutti 2014-04-21 14:11:28 +02:00
parent 1e1c4fe168
commit 05871d5b0b
338 changed files with 371542 additions and 149 deletions

View File

@ -189,6 +189,17 @@ if test "x$with_editline" = xyes; then
fi
fi
# --enable-klu: Use KLU linear systems solver
AC_ARG_ENABLE([klu],
[AS_HELP_STRING([--enable-klu], [Use KLU linear systems solver])])
# Add KLU solver to ngspice
if test "x$enable_klu" = xyes; then
AC_DEFINE(KLU, [], [Define if we want KLU linear systems solver])
AC_MSG_WARN([KLU solver enabled])
fi
AM_CONDITIONAL([KLU_WANTED], [test "x$enable_klu" = xyes])
# Enable maintainer commands only if requested
AM_MAINTAINER_MODE
@ -1138,6 +1149,7 @@ AC_CONFIG_FILES([Makefile
src/maths/deriv/Makefile
src/maths/poly/Makefile
src/maths/sparse/Makefile
src/maths/KLU/Makefile
src/misc/Makefile
src/xspice/Makefile
src/xspice/cm/Makefile

View File

@ -0,0 +1,721 @@
* ISCAS85 benchmark circuit SPICE netlist
* generated by spicegen.pl 1.0
* by Jingye Xu @ VLSI group, Dept of ECE, UIC
.INCLUDE ../../technology/45nm_HP.pm
.OPTIONS GMIN=1e-015 ABSTOL=1e-13 ACCT
* the voltage souces:
Vdd vdd gnd DC 1.8
* the input voltage sources
V1 g21 gnd pulse(0 1 0p 200p 200p 1n 2n)
V2 g18 gnd pulse(0 1 0p 200p 200p 1n 2n)
V3 g31 gnd pulse(0 1 0p 200p 200p 1n 2n)
V4 g17 gnd pulse(0 1 0p 200p 200p 1n 2n)
V5 g27 gnd pulse(0 1 0p 200p 200p 1n 2n)
V6 g11 gnd pulse(0 1 0p 200p 200p 1n 2n)
V7 g22 gnd pulse(0 1 0p 200p 200p 1n 2n)
V8 g32 gnd pulse(0 1 0p 200p 200p 1n 2n)
V9 g30 gnd pulse(0 1 0p 200p 200p 1n 2n)
V10 g4 gnd pulse(0 1 0p 200p 200p 1n 2n)
V11 g12 gnd pulse(0 1 0p 200p 200p 1n 2n)
V12 g29 gnd pulse(0 1 0p 200p 200p 1n 2n)
V13 g24 gnd pulse(0 1 0p 200p 200p 1n 2n)
V14 g39 gnd pulse(0 1 0p 200p 200p 1n 2n)
V15 g38 gnd pulse(0 1 0p 200p 200p 1n 2n)
V16 g20 gnd pulse(0 1 0p 200p 200p 1n 2n)
V17 g5 gnd pulse(0 1 0p 200p 200p 1n 2n)
V18 g35 gnd pulse(0 1 0p 200p 200p 1n 2n)
V19 g23 gnd pulse(0 1 0p 200p 200p 1n 2n)
V20 g13 gnd pulse(0 1 0p 200p 200p 1n 2n)
V21 g2 gnd pulse(0 1 0p 200p 200p 1n 2n)
V22 g37 gnd pulse(0 1 0p 200p 200p 1n 2n)
V23 g41 gnd pulse(0 1 0p 200p 200p 1n 2n)
V24 g9 gnd pulse(0 1 0p 200p 200p 1n 2n)
V25 g40 gnd pulse(0 1 0p 200p 200p 1n 2n)
V26 g14 gnd pulse(0 1 0p 200p 200p 1n 2n)
V27 g36 gnd pulse(0 1 0p 200p 200p 1n 2n)
V28 g19 gnd pulse(0 1 0p 200p 200p 1n 2n)
V29 g8 gnd pulse(0 1 0p 200p 200p 1n 2n)
V30 g3 gnd pulse(0 1 0p 200p 200p 1n 2n)
V31 g26 gnd pulse(0 1 0p 200p 200p 1n 2n)
V32 g16 gnd pulse(0 1 0p 200p 200p 1n 2n)
V33 g10 gnd pulse(0 1 0p 200p 200p 1n 2n)
V34 g6 gnd pulse(0 1 0p 200p 200p 1n 2n)
V35 g1 gnd pulse(0 1 0p 200p 200p 1n 2n)
V36 g28 gnd pulse(0 1 0p 200p 200p 1n 2n)
V37 g25 gnd pulse(0 1 0p 200p 200p 1n 2n)
V38 g15 gnd pulse(0 1 0p 200p 200p 1n 2n)
V39 g33 gnd pulse(0 1 0p 200p 200p 1n 2n)
V40 g7 gnd pulse(0 1 0p 200p 200p 1n 2n)
V41 g34 gnd pulse(0 1 0p 200p 200p 1n 2n)
X101 g20 g356 vdd gnd g422 nand2
X366 g975 g991 vdd gnd x72 and2
X467 g17 g1180 vdd gnd g1260 nand2
X194 g588 g589 vdd gnd g645 nand2
X2 g34 g41 vdd gnd g245 and2
X505 g1240 g1241 vdd gnd g1298 nand2
X254 g712 g748 vdd gnd g767 nand2
X428 g26 g1111 vdd gnd g1207 nand2
X234 g245 g721 vdd gnd g733 nand2
X414 g12 g1069 vdd gnd g1165 nand2
X285 g660 g812 vdd gnd g830 nand2
X130 g412 g413 vdd gnd g501 nand2
X144 g468 g471 vdd gnd g543 nand2
X159 g444 g531 vdd gnd g576 nand2
X120 g392 g393 vdd gnd g471 nand2
X31 g4 g8 vdd gnd g332 nand2
X554 g1315 vdd gnd g1347 not1
X314 g899 vdd gnd g955 not1
X189 g578 g579 vdd gnd g622 nand2
X518 g1266 g1267 vdd gnd g1311 nand2
X471 g19 g1186 vdd gnd g1264 nand2
X504 g1238 g1239 vdd gnd g1297 nand2
X302 g873 vdd gnd g943 not1
X526 g1282 g1283 vdd gnd g1319 nand2
X328 g899 vdd gnd g969 not1
X202 g612 g617 vdd gnd g669 nand2
X170 g477 g546 vdd gnd g587 nand2
X415 g13 g1072 vdd gnd g1168 nand2
X61 g21 g296 vdd gnd g382 nand2
X377 g860 g1001 vdd gnd g1054 and2
X439 g3 g1138 vdd gnd g1232 nand2
X293 g828 g829 vdd gnd g886 nand2
X89 g17 g338 vdd gnd g410 nand2
X275 g645 g797 vdd gnd g820 nand2
X280 g779 g803 vdd gnd g825 nand2
X523 g1276 g1277 vdd gnd g1316 nand2
X246 g724 g736 vdd gnd g759 nand2
X325 g899 vdd gnd g966 not1
X67 g27 g305 vdd gnd g388 nand2
X558 g1319 vdd gnd g1351 not1
X543 g1304 vdd gnd g1336 not1
X398 g899 g1026 vdd gnd g1117 and2
X218 g627 g678 vdd gnd g699 nand2
X46 g6 g272 vdd gnd g367 nand2
X228 g696 g697 vdd gnd g715 nand2
X15 g13 g14 vdd gnd g284 nand2
X58 g18 g290 vdd gnd g379 nand2
X374 g873 g996 vdd gnd g1045 and2
X113 g378 g379 vdd gnd g450 nand2
X396 g886 g1026 vdd gnd g1111 and2
X125 g402 g403 vdd gnd g486 nand2
X5 g37 g41 vdd gnd g254 and2
X383 g834 g1011 vdd gnd g1072 and2
X308 g873 vdd gnd g949 not1
X40 g28 g32 vdd gnd g359 nand2
X457 g12 g1165 vdd gnd g1250 nand2
X260 g760 g761 vdd gnd g779 nand2
X214 g612 g672 vdd gnd g695 nand2
X79 g10 g323 vdd gnd g400 nand2
X182 g513 g564 vdd gnd g599 nand2
X139 g438 g441 vdd gnd g528 nand2
X420 g18 g1087 vdd gnd g1183 nand2
X266 g645 g773 vdd gnd g797 nand2
X358 x41 x42 vdd gnd g1011 and2
X283 g657 g809 vdd gnd g828 nand2
X365 g974 g847 g860 vdd gnd x71 and3
X268 g651 g779 vdd gnd g803 nand2
X551 g1312 vdd gnd g1344 not1
X470 g1087 g1183 vdd gnd g1263 nand2
X185 g570 g571 vdd gnd g602 nand2
X44 g4 g269 vdd gnd g365 nand2
X86 g8 g332 vdd gnd g407 nand2
X14 g11 g12 vdd gnd g281 nand2
X438 g1039 g1135 vdd gnd g1231 nand2
X73 g1 g314 vdd gnd g394 nand2
X30 g11 g15 vdd gnd g329 nand2
X94 g22 g344 vdd gnd g415 nand2
X62 g22 g296 vdd gnd g383 nand2
X417 g15 g1078 vdd gnd g1174 nand2
X121 g394 g395 vdd gnd g474 nand2
X57 g17 g290 vdd gnd g378 nand2
X136 g424 g425 vdd gnd g519 nand2
X506 g1242 g1243 vdd gnd g1299 nand2
X66 g26 g302 vdd gnd g387 nand2
X368 g976 g847 g977 vdd gnd x81 and3
X236 g251 g727 vdd gnd g739 nand2
X233 g242 g718 vdd gnd g730 nand2
X525 g1280 g1281 vdd gnd g1318 nand2
X290 g820 g821 vdd gnd g847 nand2
X473 g20 g1189 vdd gnd g1266 nand2
X95 g26 g347 vdd gnd g416 nand2
X503 g1236 g1237 vdd gnd g1296 nand2
X480 g1102 g1198 vdd gnd g1273 nand2
X442 g1045 g1141 vdd gnd g1235 nand2
X47 g7 g275 vdd gnd g368 nand2
X179 g504 g561 vdd gnd g596 nand2
X276 g773 g797 vdd gnd g821 nand2
X345 g978 g979 g980 g981 vdd gnd g986 or4
X197 g594 g595 vdd gnd g654 nand2
X495 g31 g1222 vdd gnd g1288 nand2
X430 g28 g1117 vdd gnd g1213 nand2
X153 g426 g522 vdd gnd g570 nand2
X81 g3 g326 vdd gnd g402 nand2
X315 g925 vdd gnd g956 not1
X371 g834 g996 vdd gnd g1036 and2
X529 g1288 g1289 vdd gnd g1322 nand2
X397 g912 g1026 vdd gnd g1114 and2
X143 g462 g465 vdd gnd g540 nand2
X309 g886 vdd gnd g950 not1
X78 g6 g320 vdd gnd g399 nand2
X406 g4 g1045 vdd gnd g1141 nand2
X56 g16 g287 vdd gnd g377 nand2
X20 g23 g24 vdd gnd g299 nand2
X384 g847 g1011 vdd gnd g1075 and2
X209 g602 g666 vdd gnd g690 nand2
X423 g21 g1096 vdd gnd g1192 nand2
X100 g31 g353 vdd gnd g421 nand2
X510 g1250 g1251 vdd gnd g1303 nand2
X464 g1078 g1174 vdd gnd g1257 nand2
X201 g602 g607 vdd gnd g666 nand2
X537 g1298 vdd gnd g1330 not1
X265 g642 g770 vdd gnd g794 nand2
X429 g27 g1114 vdd gnd g1210 nand2
X245 g248 g736 vdd gnd g758 nand2
X517 g1264 g1265 vdd gnd g1310 nand2
X138 g432 g435 vdd gnd g525 nand2
X27 g2 g6 vdd gnd g320 nand2
X301 g847 vdd gnd g942 not1
X114 g380 g381 vdd gnd g453 nand2
X122 g396 g397 vdd gnd g477 nand2
X102 g24 g356 vdd gnd g423 nand2
X494 g1123 g1219 vdd gnd g1287 nand2
X4 g36 g41 vdd gnd g251 and2
X219 g632 g681 vdd gnd g700 nand2
X296 g826 g827 vdd gnd g925 nand2
X230 g700 g701 vdd gnd g721 nand2
X213 g602 g672 vdd gnd g694 nand2
X400 g886 g1031 vdd gnd g1123 and2
X200 g600 g601 vdd gnd g663 nand2
X108 g368 g369 vdd gnd g435 nand2
X444 g1048 g1144 vdd gnd g1237 nand2
X522 g1274 g1275 vdd gnd g1315 nand2
X156 g435 g525 vdd gnd g573 nand2
X351 g899 g986 vdd gnd x22 and2
X412 g10 g1063 vdd gnd g1159 nand2
X132 g416 g417 vdd gnd g507 nand2
X437 g2 g1135 vdd gnd g1230 nand2
X180 g507 g561 vdd gnd g597 nand2
X141 g450 g453 vdd gnd g534 nand2
X41 g1 g266 vdd gnd g362 nand2
X278 g776 g800 vdd gnd g823 nand2
X295 g830 g831 vdd gnd g912 nand2
X13 g9 g10 vdd gnd g278 nand2
X37 g19 g23 vdd gnd g350 nand2
X382 g873 g1006 vdd gnd g1069 and2
X252 g709 g745 vdd gnd g765 nand2
X552 g1313 vdd gnd g1345 not1
X240 g263 g715 vdd gnd g751 nand2
X107 g366 g367 vdd gnd g432 nand2
X481 g24 g1201 vdd gnd g1274 nand2
X544 g1305 vdd gnd g1337 not1
X164 g459 g537 vdd gnd g581 nand2
X60 g20 g293 vdd gnd g381 nand2
X247 g251 g739 vdd gnd g760 nand2
X469 g18 g1183 vdd gnd g1262 nand2
X524 g1278 g1279 vdd gnd g1317 nand2
X49 g9 g278 vdd gnd g370 nand2
X264 g768 g769 vdd gnd g791 nand2
X443 g5 g1144 vdd gnd g1236 nand2
X241 g242 g730 vdd gnd g754 nand2
X279 g651 g803 vdd gnd g824 nand2
X375 g834 g1001 vdd gnd g1048 and2
X326 g886 vdd gnd g967 not1
X39 g20 g24 vdd gnd g356 nand2
X116 g384 g385 vdd gnd g459 nand2
X225 g690 g691 vdd gnd g706 nand2
X172 g483 g549 vdd gnd g589 nand2
X426 g24 g1105 vdd gnd g1201 nand2
X93 g18 g344 vdd gnd g414 nand2
X465 g16 g1177 vdd gnd g1258 nand2
X344 g925 g967 g968 g969 vdd gnd g985 and4
X29 g3 g7 vdd gnd g326 nand2
X9 g1 g2 vdd gnd g266 nand2
X157 g438 g528 vdd gnd g574 nand2
X323 g925 vdd gnd g964 not1
X284 g785 g809 vdd gnd g829 nand2
X300 g834 vdd gnd g941 not1
X546 g1307 vdd gnd g1339 not1
X74 g5 g314 vdd gnd g395 nand2
X488 g1114 g1210 vdd gnd g1281 nand2
X316 g912 vdd gnd g957 not1
X472 g1090 g1186 vdd gnd g1265 nand2
X51 g11 g281 vdd gnd g372 nand2
X557 g1318 vdd gnd g1350 not1
X69 g29 g308 vdd gnd g390 nand2
X408 g6 g1051 vdd gnd g1147 nand2
X208 g627 g637 vdd gnd g687 nand2
X431 g29 g1120 vdd gnd g1216 nand2
X154 g429 g522 vdd gnd g571 nand2
X390 g899 g1016 vdd gnd g1093 and2
X493 g30 g1219 vdd gnd g1286 nand2
X332 g860 vdd gnd g973 not1
X210 g607 g666 vdd gnd g691 nand2
X381 g860 g1006 vdd gnd g1066 and2
X256 g715 g751 vdd gnd g769 nand2
X177 g498 g558 vdd gnd g594 nand2
X387 g925 g1016 vdd gnd g1084 and2
X196 g592 g593 vdd gnd g651 nand2
X498 g1129 g1225 vdd gnd g1291 nand2
X287 g663 g815 vdd gnd g832 nand2
X59 g19 g293 vdd gnd g380 nand2
X451 g9 g1156 vdd gnd g1244 nand2
X450 g1057 g1153 vdd gnd g1243 nand2
X68 g28 g305 vdd gnd g389 nand2
X92 g29 g341 vdd gnd g413 nand2
X131 g414 g415 vdd gnd g504 nand2
X401 g912 g1031 vdd gnd g1126 and2
X422 g20 g1093 vdd gnd g1189 nand2
X445 g6 g1147 vdd gnd g1238 nand2
X337 g938 g939 g940 g873 vdd gnd g978 and4
X255 g263 g751 vdd gnd g768 nand2
X352 x21 x22 vdd gnd g1001 and2
X342 g961 g962 g912 g963 vdd gnd g983 and4
X48 g8 g275 vdd gnd g369 nand2
X475 g21 g1192 vdd gnd g1268 nand2
X212 g617 g669 vdd gnd g693 nand2
X38 g27 g31 vdd gnd g353 nand2
X75 g9 g317 vdd gnd g396 nand2
X363 g873 g991 vdd gnd x62 and2
X21 g25 g26 vdd gnd g302 nand2
X8 g40 g41 vdd gnd g263 and2
X80 g14 g323 vdd gnd g401 nand2
X3 g35 g41 vdd gnd g248 and2
X292 g824 g825 vdd gnd g873 nand2
X198 g596 g597 vdd gnd g657 nand2
X12 g7 g8 vdd gnd g275 nand2
X413 g11 g1066 vdd gnd g1162 nand2
X373 g860 g996 vdd gnd g1042 and2
X253 g260 g748 vdd gnd g766 nand2
X360 g971 g991 vdd gnd x52 and2
X391 g925 g1021 vdd gnd g1096 and2
X123 g398 g399 vdd gnd g480 nand2
X183 g516 g567 vdd gnd g600 nand2
X188 g576 g577 vdd gnd g617 nand2
X330 g873 vdd gnd g971 not1
X399 g925 g1031 vdd gnd g1120 and2
X378 g873 g1001 vdd gnd g1057 and2
X462 g1075 g1171 vdd gnd g1255 nand2
X339 g944 g847 g945 g946 vdd gnd g980 and4
X545 g1306 vdd gnd g1338 not1
X281 g654 g806 vdd gnd g826 nand2
X211 g612 g669 vdd gnd g692 nand2
X171 g480 g549 vdd gnd g588 nand2
X409 g7 g1054 vdd gnd g1150 nand2
X191 g582 g583 vdd gnd g632 nand2
X150 g504 g507 vdd gnd g561 nand2
X427 g25 g1108 vdd gnd g1204 nand2
X514 g1258 g1259 vdd gnd g1307 nand2
X468 g1084 g1180 vdd gnd g1261 nand2
X317 g925 vdd gnd g958 not1
X88 g16 g335 vdd gnd g409 nand2
X235 g248 g724 vdd gnd g736 nand2
X207 g622 g632 vdd gnd g684 nand2
X343 g964 g886 g965 g966 vdd gnd g984 and4
X124 g400 g401 vdd gnd g483 nand2
X178 g501 g558 vdd gnd g595 nand2
X519 g1268 g1269 vdd gnd g1312 nand2
X482 g1105 g1201 vdd gnd g1275 nand2
X226 g692 g693 vdd gnd g709 nand2
X306 g847 vdd gnd g947 not1
X238 g257 g709 vdd gnd g745 nand2
X263 g766 g767 vdd gnd g788 nand2
X158 g441 g528 vdd gnd g575 nand2
X319 g912 vdd gnd g960 not1
X36 g26 g30 vdd gnd g347 nand2
X436 g1036 g1132 vdd gnd g1229 nand2
X489 g28 g1213 vdd gnd g1282 nand2
X199 g598 g599 vdd gnd g660 nand2
X388 g886 g1016 vdd gnd g1087 and2
X410 g8 g1057 vdd gnd g1153 nand2
X338 g941 g942 g860 g943 vdd gnd g979 and4
X261 g762 g763 vdd gnd g782 nand2
X35 g18 g22 vdd gnd g344 nand2
X215 g607 g675 vdd gnd g696 nand2
X322 g899 vdd gnd g963 not1
X453 g10 g1159 vdd gnd g1246 nand2
X96 g30 g347 vdd gnd g417 nand2
X446 g1051 g1147 vdd gnd g1239 nand2
X70 g30 g308 vdd gnd g391 nand2
X500 g1230 g1231 vdd gnd g1293 nand2
X535 g1296 vdd gnd g1328 not1
X324 g912 vdd gnd g965 not1
X369 g873 g991 vdd gnd x82 and2
X492 g1120 g1216 vdd gnd g1285 nand2
X299 g860 vdd gnd g940 not1
X559 g1320 vdd gnd g1352 not1
X539 g1300 vdd gnd g1332 not1
X389 g912 g1016 vdd gnd g1090 and2
X305 g873 vdd gnd g946 not1
X1 g33 g41 vdd gnd g242 and2
X105 g362 g363 vdd gnd g426 nand2
X353 g954 g886 g912 vdd gnd x31 and3
X206 g632 g637 vdd gnd g681 nand2
X229 g698 g699 vdd gnd g718 nand2
X509 g1248 g1249 vdd gnd g1302 nand2
X186 g572 g573 vdd gnd g607 nand2
X549 g1310 vdd gnd g1342 not1
X163 g456 g537 vdd gnd g580 nand2
X392 g886 g1021 vdd gnd g1099 and2
X531 g1292 vdd gnd g1324 not1
X329 g847 vdd gnd g970 not1
X402 g899 g1031 vdd gnd g1129 and2
X483 g25 g1204 vdd gnd g1276 nand2
X269 g654 g782 vdd gnd g806 nand2
X117 g386 g387 vdd gnd g462 nand2
X341 g958 g959 g960 g899 vdd gnd g982 and4
X223 g627 g687 vdd gnd g704 nand2
X129 g410 g411 vdd gnd g498 nand2
X550 g1311 vdd gnd g1343 not1
X76 g13 g317 vdd gnd g397 nand2
X23 g29 g30 vdd gnd g308 nand2
X271 g660 g788 vdd gnd g812 nand2
X311 g886 vdd gnd g952 not1
X555 g1316 vdd gnd g1348 not1
X82 g7 g326 vdd gnd g403 nand2
X259 g758 g759 vdd gnd g776 nand2
X289 g818 g819 vdd gnd g834 nand2
X441 g4 g1141 vdd gnd g1234 nand2
X165 g462 g540 vdd gnd g582 nand2
X318 g886 vdd gnd g959 not1
X42 g2 g266 vdd gnd g363 nand2
X155 g432 g525 vdd gnd g572 nand2
X243 g245 g733 vdd gnd g756 nand2
X435 g1 g1132 vdd gnd g1228 nand2
X133 g418 g419 vdd gnd g510 nand2
X91 g25 g341 vdd gnd g412 nand2
X258 g756 g757 vdd gnd g773 nand2
X474 g1093 g1189 vdd gnd g1267 nand2
X237 g254 g706 vdd gnd g742 nand2
X347 g925 g950 g912 vdd gnd x11 and3
X548 g1309 vdd gnd g1341 not1
X174 g489 g552 vdd gnd g591 nand2
X424 g22 g1099 vdd gnd g1195 nand2
X491 g29 g1216 vdd gnd g1284 nand2
X115 g382 g383 vdd gnd g456 nand2
X10 g3 g4 vdd gnd g269 nand2
X521 g1272 g1273 vdd gnd g1314 nand2
X181 g510 g564 vdd gnd g598 nand2
X257 g754 g755 vdd gnd g770 nand2
X34 g25 g29 vdd gnd g341 nand2
X77 g2 g320 vdd gnd g398 nand2
X249 g254 g742 vdd gnd g762 nand2
X540 g1301 vdd gnd g1333 not1
X33 g17 g21 vdd gnd g338 nand2
X128 g408 g409 vdd gnd g495 nand2
X166 g465 g540 vdd gnd g583 nand2
X248 g727 g739 vdd gnd g761 nand2
X562 g1323 vdd gnd g1355 not1
X142 g456 g459 vdd gnd g537 nand2
X168 g471 g543 vdd gnd g585 nand2
X224 g637 g687 vdd gnd g705 nand2
X277 g648 g800 vdd gnd g822 nand2
X106 g364 g365 vdd gnd g429 nand2
X118 g388 g389 vdd gnd g465 nand2
X354 g955 g986 vdd gnd x32 and2
X149 g498 g501 vdd gnd g558 nand2
X90 g21 g338 vdd gnd g411 nand2
X335 g834 vdd gnd g976 not1
X376 g847 g1001 vdd gnd g1051 and2
X393 g912 g1021 vdd gnd g1102 and2
X251 g257 g745 vdd gnd g764 nand2
X530 g1290 g1291 vdd gnd g1323 nand2
X83 g11 g329 vdd gnd g404 nand2
X463 g15 g1174 vdd gnd g1256 nand2
X321 g886 vdd gnd g962 not1
X270 g657 g785 vdd gnd g809 nand2
X286 g788 g812 vdd gnd g831 nand2
X547 g1308 vdd gnd g1340 not1
X458 g1069 g1165 vdd gnd g1251 nand2
X22 g27 g28 vdd gnd g305 nand2
X147 g486 g489 vdd gnd g552 nand2
X340 g834 g947 g948 g949 vdd gnd g981 and4
X43 g3 g269 vdd gnd g364 nand2
X418 g16 g1081 vdd gnd g1177 nand2
X310 g899 vdd gnd g951 not1
X459 g13 g1168 vdd gnd g1252 nand2
X411 g9 g1060 vdd gnd g1156 nand2
X193 g586 g587 vdd gnd g642 nand2
X380 g847 g1006 vdd gnd g1063 and2
X242 g718 g730 vdd gnd g755 nand2
X111 g374 g375 vdd gnd g444 nand2
X513 g1256 g1257 vdd gnd g1306 nand2
X477 g22 g1195 vdd gnd g1270 nand2
X28 g10 g14 vdd gnd g323 nand2
X536 g1297 vdd gnd g1329 not1
X50 g10 g278 vdd gnd g371 nand2
X152 g516 g519 vdd gnd g567 nand2
X499 g1228 g1229 vdd gnd g1292 nand2
X440 g1042 g1138 vdd gnd g1233 nand2
X205 g622 g627 vdd gnd g678 nand2
X294 g832 g833 vdd gnd g899 nand2
X52 g12 g281 vdd gnd g373 nand2
X173 g486 g552 vdd gnd g590 nand2
X272 g663 g791 vdd gnd g815 nand2
X452 g1060 g1156 vdd gnd g1245 nand2
X476 g1096 g1192 vdd gnd g1269 nand2
X484 g1108 g1204 vdd gnd g1277 nand2
X447 g7 g1150 vdd gnd g1240 nand2
X448 g1054 g1150 vdd gnd g1241 nand2
X331 g847 vdd gnd g972 not1
X348 g951 g986 vdd gnd x12 and2
X520 g1270 g1271 vdd gnd g1313 nand2
X162 g453 g534 vdd gnd g579 nand2
X355 x31 x32 vdd gnd g1006 and2
X364 x61 x62 vdd gnd g1021 and2
X403 g1 g1036 vdd gnd g1132 nand2
X385 g860 g1011 vdd gnd g1078 and2
X320 g925 vdd gnd g961 not1
X87 g12 g335 vdd gnd g408 nand2
X356 g956 g886 g957 vdd gnd x41 and3
X184 g519 g567 vdd gnd g601 nand2
X507 g1244 g1245 vdd gnd g1300 nand2
X359 g834 g970 g860 vdd gnd x51 and3
X135 g422 g423 vdd gnd g516 nand2
X63 g23 g299 vdd gnd g384 nand2
X282 g782 g806 vdd gnd g827 nand2
X333 g834 vdd gnd g974 not1
X291 g822 g823 vdd gnd g860 nand2
X167 g468 g543 vdd gnd g584 nand2
X455 g11 g1162 vdd gnd g1248 nand2
X556 g1317 vdd gnd g1349 not1
X460 g1072 g1168 vdd gnd g1253 nand2
X103 g28 g359 vdd gnd g424 nand2
X239 g260 g712 vdd gnd g748 nand2
X434 g32 g1129 vdd gnd g1225 nand2
X145 g474 g477 vdd gnd g546 nand2
X16 g15 g16 vdd gnd g287 nand2
X312 g912 vdd gnd g953 not1
X487 g27 g1210 vdd gnd g1280 nand2
X497 g32 g1225 vdd gnd g1290 nand2
X65 g25 g302 vdd gnd g386 nand2
X407 g5 g1048 vdd gnd g1144 nand2
X425 g23 g1102 vdd gnd g1198 nand2
X127 g406 g407 vdd gnd g492 nand2
X72 g32 g311 vdd gnd g393 nand2
X404 g2 g1039 vdd gnd g1135 nand2
X288 g791 g815 vdd gnd g833 nand2
X386 g873 g1011 vdd gnd g1081 and2
X516 g1262 g1263 vdd gnd g1309 nand2
X533 g1294 vdd gnd g1326 not1
X112 g376 g377 vdd gnd g447 nand2
X303 g834 vdd gnd g944 not1
X541 g1302 vdd gnd g1334 not1
X304 g860 vdd gnd g945 not1
X313 g925 vdd gnd g954 not1
X137 g426 g429 vdd gnd g522 nand2
X327 g912 vdd gnd g968 not1
X532 g1293 vdd gnd g1325 not1
X478 g1099 g1195 vdd gnd g1271 nand2
X146 g480 g483 vdd gnd g549 nand2
X511 g1252 g1253 vdd gnd g1304 nand2
X55 g15 g287 vdd gnd g376 nand2
X25 g1 g5 vdd gnd g314 nand2
X84 g15 g329 vdd gnd g405 nand2
X19 g21 g22 vdd gnd g296 nand2
X367 x71 x72 vdd gnd g1026 and2
X273 g642 g794 vdd gnd g818 nand2
X372 g847 g996 vdd gnd g1039 and2
X394 g899 g1021 vdd gnd g1105 and2
X349 x11 x12 vdd gnd g996 and2
X161 g450 g534 vdd gnd g578 nand2
X490 g1117 g1213 vdd gnd g1283 nand2
X528 g1286 g1287 vdd gnd g1321 nand2
X538 g1299 vdd gnd g1331 not1
X160 g447 g531 vdd gnd g577 nand2
X190 g580 g581 vdd gnd g627 nand2
X449 g8 g1153 vdd gnd g1242 nand2
X336 g860 vdd gnd g977 not1
X297 g834 vdd gnd g938 not1
X502 g1234 g1235 vdd gnd g1295 nand2
X553 g1314 vdd gnd g1346 not1
X7 g39 g41 vdd gnd g260 and2
X560 g1321 vdd gnd g1353 not1
X216 g617 g675 vdd gnd g697 nand2
X176 g495 g555 vdd gnd g593 nand2
X98 g23 g350 vdd gnd g419 nand2
X204 g607 g617 vdd gnd g675 nand2
X221 g622 g684 vdd gnd g702 nand2
X232 g704 g705 vdd gnd g727 nand2
X26 g9 g13 vdd gnd g317 nand2
X54 g14 g284 vdd gnd g375 nand2
X244 g721 g733 vdd gnd g757 nand2
X262 g764 g765 vdd gnd g785 nand2
X18 g19 g20 vdd gnd g293 nand2
X419 g17 g1084 vdd gnd g1180 nand2
X298 g847 vdd gnd g939 not1
X461 g14 g1171 vdd gnd g1254 nand2
X126 g404 g405 vdd gnd g489 nand2
X203 g602 g612 vdd gnd g672 nand2
X433 g31 g1126 vdd gnd g1222 nand2
X220 g637 g681 vdd gnd g701 nand2
X110 g372 g373 vdd gnd g441 nand2
X362 g834 g972 g973 vdd gnd x61 and3
X379 g834 g1006 vdd gnd g1060 and2
X53 g13 g284 vdd gnd g374 nand2
X346 g982 g983 g984 g985 vdd gnd g991 or4
X496 g1126 g1222 vdd gnd g1289 nand2
X501 g1232 g1233 vdd gnd g1294 nand2
X134 g420 g421 vdd gnd g513 nand2
X17 g17 g18 vdd gnd g290 nand2
X187 g574 g575 vdd gnd g612 nand2
X334 g873 vdd gnd g975 not1
X485 g26 g1207 vdd gnd g1278 nand2
X6 g38 g41 vdd gnd g257 and2
X64 g24 g299 vdd gnd g385 nand2
X109 g370 g371 vdd gnd g438 nand2
X97 g19 g350 vdd gnd g418 nand2
X32 g12 g16 vdd gnd g335 nand2
X192 g584 g585 vdd gnd g637 nand2
X405 g3 g1042 vdd gnd g1138 nand2
X71 g31 g311 vdd gnd g392 nand2
X140 g444 g447 vdd gnd g531 nand2
X148 g492 g495 vdd gnd g555 nand2
X274 g770 g794 vdd gnd g819 nand2
X222 g632 g684 vdd gnd g703 nand2
X534 g1295 vdd gnd g1327 not1
X466 g1081 g1177 vdd gnd g1259 nand2
X432 g30 g1123 vdd gnd g1219 nand2
X24 g31 g32 vdd gnd g311 nand2
X515 g1260 g1261 vdd gnd g1308 nand2
X151 g510 g513 vdd gnd g564 nand2
X227 g694 g695 vdd gnd g712 nand2
X486 g1111 g1207 vdd gnd g1279 nand2
X85 g4 g332 vdd gnd g406 nand2
X267 g648 g776 vdd gnd g800 nand2
X370 x81 x82 vdd gnd g1031 and2
X169 g474 g546 vdd gnd g586 nand2
X11 g5 g6 vdd gnd g272 nand2
X350 g925 g952 g953 vdd gnd x21 and3
X456 g1066 g1162 vdd gnd g1249 nand2
X217 g622 g678 vdd gnd g698 nand2
X307 g860 vdd gnd g948 not1
X542 g1303 vdd gnd g1335 not1
X527 g1284 g1285 vdd gnd g1320 nand2
X250 g706 g742 vdd gnd g763 nand2
X195 g590 g591 vdd gnd g648 nand2
X421 g19 g1090 vdd gnd g1186 nand2
X357 g899 g986 vdd gnd x42 and2
X119 g390 g391 vdd gnd g468 nand2
X99 g27 g353 vdd gnd g420 nand2
X45 g5 g272 vdd gnd g366 nand2
X454 g1063 g1159 vdd gnd g1247 nand2
X508 g1246 g1247 vdd gnd g1301 nand2
X512 g1254 g1255 vdd gnd g1305 nand2
X231 g702 g703 vdd gnd g724 nand2
X175 g492 g555 vdd gnd g592 nand2
X479 g23 g1198 vdd gnd g1272 nand2
X395 g925 g1026 vdd gnd g1108 and2
X104 g32 g359 vdd gnd g425 nand2
X416 g14 g1075 vdd gnd g1171 nand2
X361 x51 x52 vdd gnd g1016 and2
X561 g1322 vdd gnd g1354 not1
.subckt and3 a b c vdd vss z
m01 08 a vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m02 n1 a vss vss nmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m03 vdd b 08 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m04 sig6 b n1 vss nmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m05 08 c vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m06 08 c sig6 vss nmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m07 vdd 08 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m08 vss 08 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 08 vss 1.142f
c5 a vss 0.539f
c7 b vss 0.609f
c8 c vss 0.651f
c3 z vss 0.745f
.ends
.subckt or4 a b c d vdd vss z
m01 sig8 a vdd vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m02 vdd a 05 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m03 sig1 a vss vss nmos l=0.12u w=0.33u as=0.08745p ad=0.08745p ps=1.19u pd=1.19u
m04 n2 b sig8 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m05 05 b 08 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m06 vss b sig1 vss nmos l=0.12u w=0.33u as=0.08745p ad=0.08745p ps=1.19u pd=1.19u
m07 10 c n2 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m08 08 c 11 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m09 sig1 c vss vss nmos l=0.12u w=0.33u as=0.08745p ad=0.08745p ps=1.19u pd=1.19u
m10 sig1 d 10 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m11 11 d sig1 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m12 vss d sig1 vss nmos l=0.12u w=0.33u as=0.08745p ad=0.08745p ps=1.19u pd=1.19u
m13 vdd sig1 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m14 vss sig1 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 a vss 1.356f
c5 b vss 1.229f
c6 c vss 1.043f
c7 d vss 0.797f
c1 sig1 vss 1.003f
c3 z vss 0.701f
.ends
.subckt xnr2v0x1 a b vdd vss z
m01 z b sig3 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m02 bn sig3 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
m03 sig3 a vdd vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m04 vdd b bn vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m05 z bn sig3 vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
m06 vdd sig3 n1 vdd pmos l=0.12u w=1.54u as=0.4081p ad=0.4081p ps=3.61u pd=3.61u
m07 sig3 a vss vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
m08 n1 bn z vdd pmos l=0.12u w=1.54u as=0.4081p ad=0.4081p ps=3.61u pd=3.61u
m09 vss b bn vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 a vss 0.389f
c2 bn vss 1.593f
c5 b vss 0.840f
c3 sig3 vss 0.618f
c6 z vss 0.627f
.ends
.subckt nand2 a b vdd vss z
m01 vdd a z vdd pmos l=0.12u w=0.77u as=0.20405p ad=0.20405p ps=2.07u pd=2.07u
m02 vss a sig3 vss nmos l=0.12u w=0.66u as=0.1749p ad=0.1749p ps=1.85u pd=1.85u
m03 z b vdd vdd pmos l=0.12u w=0.77u as=0.20405p ad=0.20405p ps=2.07u pd=2.07u
m04 sig3 b z vss nmos l=0.12u w=0.66u as=0.1749p ad=0.1749p ps=1.85u pd=1.85u
c4 a vss 0.549f
c5 b vss 0.578f
c1 z vss 0.609f
.ends
.subckt and4 a b c d vdd vss z
m01 10 a vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m02 n1 a vss vss nmos l=0.12u w=0.88u as=0.2332p ad=0.2332p ps=2.29u pd=2.29u
m03 vdd b 10 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m04 sig7 b n1 vss nmos l=0.12u w=0.88u as=0.2332p ad=0.2332p ps=2.29u pd=2.29u
m05 10 c vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m06 n3 c sig7 vss nmos l=0.12u w=0.88u as=0.2332p ad=0.2332p ps=2.29u pd=2.29u
m07 vdd d 10 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m08 10 d n3 vss nmos l=0.12u w=0.88u as=0.2332p ad=0.2332p ps=2.29u pd=2.29u
m09 vdd 10 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m10 vss 10 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 10 vss 0.940f
c5 a vss 0.674f
c8 b vss 0.541f
c9 c vss 0.622f
c10 d vss 0.791f
c3 z vss 0.765f
.ends
.subckt and2 a b vdd vss z
m01 06 a vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m02 n1 a vss vss nmos l=0.12u w=0.605u as=0.160325p ad=0.160325p ps=1.74u pd=1.74u
m03 vdd b 06 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m04 06 b n1 vss nmos l=0.12u w=0.605u as=0.160325p ad=0.160325p ps=1.74u pd=1.74u
m05 vdd 06 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m06 vss 06 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 06 vss 0.724f
c5 a vss 0.663f
c6 b vss 0.538f
c3 z vss 0.595f
.ends
.subckt not1 a vdd vss z
m01 vdd a z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m02 vss a z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c3 a vss 0.384f
c2 z vss 0.576f
.ends
* simulation command:
.tran 1ps 1ns
.print tran V(g1326) V(g1339) V(g1349) V(g1352) V(g1350) V(g1340) V(g1332) V(g1351) V(g1327) V(g1345) V(g1324) V(g1333) V(g1344) V(g1334) V(g1346) V(g1325) V(g1343) V(g1347) V(g1335) V(g1342) V(g1353) V(g1354) V(g1329) V(g1348) V(g1328) V(g1341) V(g1336) V(g1330) V(g1337) V(g1331) V(g1338) V(g1355)
.end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,429 @@
* ISCAS85 benchmark circuit SPICE netlist
* generated by spicegen.pl 1.0
* by Jingye Xu @ VLSI group, Dept of ECE, UIC
.INCLUDE ../../technology/45nm_HP.pm
.OPTIONS GMIN=1e-015 ABSTOL=1e-13 ACCT
* the voltage souces:
Vdd vdd gnd DC 1.8
* the input voltage sources
V1 g35 gnd pulse(0 1 0p 200p 200p 1n 2n)
V2 g21 gnd pulse(0 1 0p 200p 200p 1n 2n)
V3 g18 gnd pulse(0 1 0p 200p 200p 1n 2n)
V4 g23 gnd pulse(0 1 0p 200p 200p 1n 2n)
V5 g13 gnd pulse(0 1 0p 200p 200p 1n 2n)
V6 g2 gnd pulse(0 1 0p 200p 200p 1n 2n)
V7 g31 gnd pulse(0 1 0p 200p 200p 1n 2n)
V8 g9 gnd pulse(0 1 0p 200p 200p 1n 2n)
V9 g17 gnd pulse(0 1 0p 200p 200p 1n 2n)
V10 g27 gnd pulse(0 1 0p 200p 200p 1n 2n)
V11 g14 gnd pulse(0 1 0p 200p 200p 1n 2n)
V12 g36 gnd pulse(0 1 0p 200p 200p 1n 2n)
V13 g19 gnd pulse(0 1 0p 200p 200p 1n 2n)
V14 g8 gnd pulse(0 1 0p 200p 200p 1n 2n)
V15 g3 gnd pulse(0 1 0p 200p 200p 1n 2n)
V16 g26 gnd pulse(0 1 0p 200p 200p 1n 2n)
V17 g16 gnd pulse(0 1 0p 200p 200p 1n 2n)
V18 g11 gnd pulse(0 1 0p 200p 200p 1n 2n)
V19 g22 gnd pulse(0 1 0p 200p 200p 1n 2n)
V20 g32 gnd pulse(0 1 0p 200p 200p 1n 2n)
V21 g30 gnd pulse(0 1 0p 200p 200p 1n 2n)
V22 g10 gnd pulse(0 1 0p 200p 200p 1n 2n)
V23 g6 gnd pulse(0 1 0p 200p 200p 1n 2n)
V24 g1 gnd pulse(0 1 0p 200p 200p 1n 2n)
V25 g28 gnd pulse(0 1 0p 200p 200p 1n 2n)
V26 g25 gnd pulse(0 1 0p 200p 200p 1n 2n)
V27 g4 gnd pulse(0 1 0p 200p 200p 1n 2n)
V28 g15 gnd pulse(0 1 0p 200p 200p 1n 2n)
V29 g12 gnd pulse(0 1 0p 200p 200p 1n 2n)
V30 g29 gnd pulse(0 1 0p 200p 200p 1n 2n)
V31 g33 gnd pulse(0 1 0p 200p 200p 1n 2n)
V32 g7 gnd pulse(0 1 0p 200p 200p 1n 2n)
V33 g24 gnd pulse(0 1 0p 200p 200p 1n 2n)
V34 g34 gnd pulse(0 1 0p 200p 200p 1n 2n)
V35 g20 gnd pulse(0 1 0p 200p 200p 1n 2n)
V36 g5 gnd pulse(0 1 0p 200p 200p 1n 2n)
X101 x246 y246 vdd gnd g246 nand2
X261 g378 g418 g421 g425 vdd gnd g432 nand4
X194 g308 g281 vdd gnd g339 xor2
X215 g333 g303 vdd gnd g350 nand2
X35 g17 g131 vdd gnd g188 nor2
X2 g2 vdd gnd g119 not1
X96 g203 g177 vdd gnd g246 xor2
X70 g203 g165 vdd gnd g232 xor2
X254 g383 g390 g404 g417 vdd gnd g425 nand4
X234 g2 g241 g332 g368 vdd gnd g377 nand4
X130 g242 g194 vdd gnd g292 nand2
X144 g293 vdd gnd g306 not1
X159 x329 y329 vdd gnd g329 nand2
X120 g235 g189 vdd gnd g272 nand2
X31 g9 g123 vdd gnd g184 nor2
X189 g278 vdd gnd z337 not1
X202 g308 vdd gnd w341 not1
X170 g269 w331 vdd gnd y331 nand2
X1 g1 vdd gnd g118 not1
X61 g203 z226 vdd gnd x226 nand2
X105 g180 vdd gnd z250 not1
X229 g358 g21 vdd gnd g372 nand2
X206 x341 y341 vdd gnd g341 nand2
X186 g318 g11 vdd gnd g336 nand2
X89 g203 g174 vdd gnd g242 xor2
X163 g308 z330 vdd gnd x330 nand2
X246 x41 x42 vdd gnd g413 and2
X117 g226 g183 vdd gnd g263 nand2
X67 g203 z229 vdd gnd x229 nand2
X223 x31 x32 x33 vdd gnd g355 and3
X129 g238 g192 vdd gnd g291 nand2
X218 g339 g306 vdd gnd g353 nand2
X46 g154 g159 g162 vdd gnd x11 and3
X228 g358 g17 vdd gnd g371 nand2
X15 g28 vdd gnd g146 not1
X58 g203 g159 vdd gnd g226 xor2
X76 g203 g168 vdd gnd g235 xor2
X113 g213 g28 vdd gnd g257 nand2
X125 g226 g184 vdd gnd g287 nand2
X23 g126 g10 vdd gnd g162 nand2
X5 g8 vdd gnd g126 not1
X40 g27 g143 vdd gnd g193 nor2
X82 g203 g171 vdd gnd g238 xor2
X259 g378 g383 g418 g396 vdd gnd g430 nand4
X260 g378 g383 g421 g424 vdd gnd g431 nand4
X165 x330 y330 vdd gnd g330 nand2
X214 g331 g302 vdd gnd g349 nand2
X79 g203 z235 vdd gnd x235 nand2
X155 g308 vdd gnd w329 not1
X42 g31 g147 vdd gnd g195 nor2
X182 g275 vdd gnd z335 not1
X243 g377 vdd gnd g412 not1
X133 g259 g263 g266 vdd gnd x21 and3
X91 g174 vdd gnd z242 not1
X258 g412 g413 vdd gnd g429 nor2
X139 g288 vdd gnd g301 not1
X237 g253 g338 g371 g14 vdd gnd g390 nand4
X174 g308 vdd gnd w333 not1
X115 g223 g157 vdd gnd g259 nand2
X10 g18 vdd gnd g135 not1
X257 g355 vdd gnd g428 not1
X181 g308 vdd gnd w335 not1
X34 g15 g131 vdd gnd g187 nor2
X77 g203 vdd gnd w235 not1
X185 x335 y335 vdd gnd g335 nand2
X44 g35 g151 vdd gnd g197 nor2
X249 g404 vdd gnd g416 not1
X86 g171 w238 vdd gnd y238 nand2
X14 g26 vdd gnd g143 not1
X33 g13 g127 vdd gnd g186 nor2
X128 g235 g190 vdd gnd g290 nand2
X73 g203 z232 vdd gnd x232 nand2
X30 g7 g123 vdd gnd g183 nor2
X248 g401 vdd gnd g415 not1
X166 g308 g269 vdd gnd g331 xor2
X94 x242 y242 vdd gnd g242 nand2
X62 g159 w226 vdd gnd y226 nand2
X121 g238 g191 vdd gnd g275 nand2
X57 x223 y223 vdd gnd g223 nand2
X224 g355 vdd gnd g358 not1
X168 g269 vdd gnd z331 not1
X142 g291 vdd gnd g304 not1
X136 x21 x22 x23 vdd gnd g295 and3
X106 g203 z250 vdd gnd x250 nand2
X66 g162 vdd gnd z229 not1
X118 g229 g185 vdd gnd g266 nand2
X149 g308 vdd gnd w328 not1
X90 g203 vdd gnd w242 not1
X236 g249 g336 g370 g10 vdd gnd g383 nand4
X233 g358 g36 vdd gnd g376 nand2
X251 g383 g414 vdd gnd g418 nand2
X95 g213 g4 vdd gnd g245 nand2
X83 g203 vdd gnd w238 not1
X47 g165 g168 g171 vdd gnd x12 and3
X179 g318 g7 vdd gnd g334 nand2
X197 g308 z339 vdd gnd x339 nand2
X153 x328 y328 vdd gnd g328 nand2
X22 g122 g6 vdd gnd g159 nand2
X81 x235 y235 vdd gnd g235 nand2
X147 g295 vdd gnd g318 not1
X43 g33 g147 vdd gnd g196 nor2
X143 g292 vdd gnd g305 not1
X193 g318 g15 vdd gnd g338 nand2
X242 g258 g345 g376 g34 vdd gnd g411 nand4
X78 g168 vdd gnd z235 not1
X111 g213 g20 vdd gnd g255 nand2
X28 g146 g30 vdd gnd g177 nand2
X56 g154 w223 vdd gnd y223 nand2
X152 g259 w328 vdd gnd y328 nand2
X50 g199 vdd gnd g203 not1
X20 g3 g119 vdd gnd g157 nor2
X205 g284 w341 vdd gnd y341 nand2
X209 g318 g31 vdd gnd g344 nand2
X173 g308 g272 vdd gnd g333 xor2
X100 g177 w246 vdd gnd y246 nand2
X52 g203 g154 vdd gnd g223 xor2
X201 g308 g284 vdd gnd g341 xor2
X245 g401 g404 g408 g411 vdd gnd x42 and4
X138 g287 vdd gnd g300 not1
X27 g142 g26 vdd gnd g174 nand2
X114 g213 g32 vdd gnd g258 nand2
X122 g242 g193 vdd gnd g278 nand2
X102 g213 g8 vdd gnd g249 nand2
X4 g6 vdd gnd g123 not1
X162 g266 vdd gnd z330 not1
X219 g341 g307 vdd gnd g354 nand2
X230 g358 g25 vdd gnd g373 nand2
X213 g330 g301 vdd gnd g348 nand2
X87 x238 y238 vdd gnd g238 nand2
X108 x250 y250 vdd gnd g250 nand2
X200 g318 g19 vdd gnd g340 nand2
X184 g275 w335 vdd gnd y335 nand2
X156 g263 vdd gnd z329 not1
X132 g250 g198 vdd gnd g294 nand2
X135 g278 g281 g284 vdd gnd x23 and3
X63 x226 y226 vdd gnd g226 nand2
X167 g308 vdd gnd w331 not1
X180 g308 g275 vdd gnd g335 xor2
X141 g290 vdd gnd g303 not1
X41 g29 g143 vdd gnd g194 nor2
X103 g203 g180 vdd gnd g250 xor2
X239 g255 g342 g373 g22 vdd gnd g401 nand4
X13 g24 vdd gnd g142 not1
X145 g294 vdd gnd g307 not1
X16 g30 vdd gnd g147 not1
X37 g21 g135 vdd gnd g190 nor2
X252 g383 g390 g415 g396 vdd gnd g421 nand4
X240 g256 g343 g374 g26 vdd gnd g404 nand4
X107 g180 w250 vdd gnd y250 nand2
X65 g203 vdd gnd w229 not1
X164 g266 w330 vdd gnd y330 nand2
X60 g159 vdd gnd z226 not1
X247 g390 vdd gnd g414 not1
X72 g165 vdd gnd z232 not1
X127 g232 g188 vdd gnd g289 nand2
X49 x11 x12 x13 vdd gnd g199 and3
X241 g257 g344 g375 g30 vdd gnd g408 nand4
X39 g25 g139 vdd gnd g192 nor2
X112 g213 g24 vdd gnd g256 nand2
X116 g223 g158 vdd gnd g262 nand2
X225 g5 g358 vdd gnd g368 nand2
X137 g262 vdd gnd g299 not1
X172 g3 g318 vdd gnd g332 nand2
X93 g174 w242 vdd gnd y242 nand2
X29 g150 g34 vdd gnd g180 nand2
X146 g295 vdd gnd g308 not1
X9 g16 vdd gnd g134 not1
X25 g134 g18 vdd gnd g168 nand2
X55 g203 z223 vdd gnd x223 nand2
X157 g308 z329 vdd gnd x329 nand2
X84 g171 vdd gnd z238 not1
X19 g118 g2 vdd gnd g154 nand2
X74 g165 w232 vdd gnd y232 nand2
X161 g308 vdd gnd w330 not1
X51 g199 vdd gnd g213 not1
X160 g308 g266 vdd gnd g330 xor2
X190 g308 z337 vdd gnd x337 nand2
X69 x229 y229 vdd gnd g229 nand2
X208 g318 g27 vdd gnd g343 nand2
X154 g308 g263 vdd gnd g329 xor2
X7 g12 vdd gnd g130 not1
X210 g318 g35 vdd gnd g345 nand2
X256 g295 vdd gnd g427 not1
X216 g335 g304 vdd gnd g351 nand2
X177 g272 w333 vdd gnd y333 nand2
X98 g177 vdd gnd z246 not1
X176 g308 z333 vdd gnd x333 nand2
X204 g308 z341 vdd gnd x341 nand2
X221 g349 g350 g351 vdd gnd x32 and3
X232 g358 g33 vdd gnd g375 nand2
X196 g281 vdd gnd z339 not1
X26 g138 g22 vdd gnd g171 nand2
X59 g203 vdd gnd w226 not1
X54 g154 vdd gnd z223 not1
X244 g378 g383 g390 g396 vdd gnd x41 and4
X18 g34 vdd gnd g151 not1
X126 g229 g186 vdd gnd g288 nand2
X203 g284 vdd gnd z341 not1
X220 g346 g347 g348 vdd gnd x31 and3
X68 g162 w229 vdd gnd y229 nand2
X110 g213 g16 vdd gnd g254 nand2
X53 g203 vdd gnd w223 not1
X92 g203 z242 vdd gnd x242 nand2
X131 g246 g196 vdd gnd g293 nand2
X255 g199 vdd gnd g426 not1
X17 g32 vdd gnd g150 not1
X134 g269 g272 g275 vdd gnd x22 and3
X187 g308 g278 vdd gnd g337 xor2
X48 g174 g177 g180 vdd gnd x13 and3
X6 g10 vdd gnd g127 not1
X212 g329 g300 vdd gnd g347 nand2
X64 g203 g162 vdd gnd g229 xor2
X38 g23 g139 vdd gnd g191 nor2
X109 g213 g12 vdd gnd g253 nand2
X32 g11 g127 vdd gnd g185 nor2
X97 g203 vdd gnd w246 not1
X192 x337 y337 vdd gnd g337 nand2
X75 x232 y232 vdd gnd g232 nand2
X21 g5 g119 vdd gnd g158 nor2
X80 g168 w235 vdd gnd y235 nand2
X8 g14 vdd gnd g131 not1
X3 g4 vdd gnd g122 not1
X198 g281 w339 vdd gnd y339 nand2
X71 g203 vdd gnd w232 not1
X12 g22 vdd gnd g139 not1
X140 g289 vdd gnd g302 not1
X253 g396 g390 g416 vdd gnd g424 nand3
X148 g308 g259 vdd gnd g328 xor2
X123 g246 g195 vdd gnd g281 nand2
X183 g308 z335 vdd gnd x335 nand2
X222 g352 g353 g354 vdd gnd x33 and3
X188 g308 vdd gnd w337 not1
X24 g130 g14 vdd gnd g165 nand2
X151 g308 z328 vdd gnd x328 nand2
X227 g358 g13 vdd gnd g370 nand2
X85 g203 z238 vdd gnd x238 nand2
X171 x331 y331 vdd gnd g331 nand2
X211 g328 g299 vdd gnd g346 nand2
X11 g20 vdd gnd g138 not1
X169 g308 z331 vdd gnd x331 nand2
X191 g278 w337 vdd gnd y337 nand2
X217 g337 g305 vdd gnd g352 nand2
X150 g259 vdd gnd z328 not1
X88 g1 g213 vdd gnd g241 nand2
X250 g408 vdd gnd g417 not1
X235 g245 g334 g369 g6 vdd gnd g378 nand4
X207 g318 g23 vdd gnd g342 nand2
X195 g308 vdd gnd w339 not1
X124 g250 g197 vdd gnd g284 nand2
X178 x333 y333 vdd gnd g333 nand2
X99 g203 z246 vdd gnd x246 nand2
X119 g232 g187 vdd gnd g269 nand2
X45 g36 g151 vdd gnd g198 nor2
X226 g358 g9 vdd gnd g369 nand2
X238 g254 g340 g372 g18 vdd gnd g396 nand4
X231 g358 g29 vdd gnd g374 nand2
X158 g263 w329 vdd gnd y329 nand2
X175 g272 vdd gnd z333 not1
X36 g19 g135 vdd gnd g189 nor2
X104 g203 vdd gnd w250 not1
X199 x339 y339 vdd gnd g339 nand2
.subckt nor2 a b vdd vss z
m01 vdd a 01 vdd pmos l=0.12u w=1.54u as=0.4081p ad=0.4081p ps=3.61u pd=3.61u
m02 vss a z vss nmos l=0.12u w=0.44u as=0.1166p ad=0.1166p ps=1.41u pd=1.41u
m03 01 b z vdd pmos l=0.12u w=1.54u as=0.4081p ad=0.4081p ps=3.61u pd=3.61u
m04 z b vss vss nmos l=0.12u w=0.44u as=0.1166p ad=0.1166p ps=1.41u pd=1.41u
c4 a vss 0.341f
c3 b vss 0.433f
c2 z vss 0.677f
.ends
.subckt and4 a b c d vdd vss z
m01 10 a vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m02 n1 a vss vss nmos l=0.12u w=0.88u as=0.2332p ad=0.2332p ps=2.29u pd=2.29u
m03 vdd b 10 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m04 sig7 b n1 vss nmos l=0.12u w=0.88u as=0.2332p ad=0.2332p ps=2.29u pd=2.29u
m05 10 c vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m06 n3 c sig7 vss nmos l=0.12u w=0.88u as=0.2332p ad=0.2332p ps=2.29u pd=2.29u
m07 vdd d 10 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m08 10 d n3 vss nmos l=0.12u w=0.88u as=0.2332p ad=0.2332p ps=2.29u pd=2.29u
m09 vdd 10 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m10 vss 10 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 10 vss 0.940f
c5 a vss 0.674f
c8 b vss 0.541f
c9 c vss 0.622f
c10 d vss 0.791f
c3 z vss 0.765f
.ends
.subckt not1 a vdd vss z
m01 vdd a z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m02 vss a z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c3 a vss 0.384f
c2 z vss 0.576f
.ends
.subckt xor2 a b vdd vss z
m01 04 a vdd vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m02 04 a vss vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
m03 vdd b bn vdd pmos l=0.12u w=1.485u as=0.393525p ad=0.393525p ps=3.5u pd=3.5u
m04 z b 04 vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
m05 vss b bn vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
m06 bn 04 z vdd pmos l=0.12u w=1.485u as=0.393525p ad=0.393525p ps=3.5u pd=3.5u
m07 vss 04 09 vss nmos l=0.12u w=0.66u as=0.1749p ad=0.1749p ps=1.85u pd=1.85u
m08 z bn 04 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m09 09 bn z vss nmos l=0.12u w=0.66u as=0.1749p ad=0.1749p ps=1.85u pd=1.85u
c6 04 vss 0.683f
c4 a vss 0.590f
c1 bn vss 0.910f
c3 b vss 1.149f
c5 z vss 0.680f
.ends
.subckt and3 a b c vdd vss z
m01 08 a vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m02 n1 a vss vss nmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m03 vdd b 08 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m04 sig6 b n1 vss nmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m05 08 c vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m06 08 c sig6 vss nmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m07 vdd 08 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m08 vss 08 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 08 vss 1.142f
c5 a vss 0.539f
c7 b vss 0.609f
c8 c vss 0.651f
c3 z vss 0.745f
.ends
.subckt nand4 a b c d vdd vss z
m01 vdd a z vdd pmos l=0.12u w=0.935u as=0.247775p ad=0.247775p ps=2.4u pd=2.4u
m02 vss a sig7 vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m03 z b vdd vdd pmos l=0.12u w=0.935u as=0.247775p ad=0.247775p ps=2.4u pd=2.4u
m04 sig7 b sig3 vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m05 vdd c z vdd pmos l=0.12u w=0.935u as=0.247775p ad=0.247775p ps=2.4u pd=2.4u
m06 sig3 c sig2 vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m07 z d vdd vdd pmos l=0.12u w=0.935u as=0.247775p ad=0.247775p ps=2.4u pd=2.4u
m08 sig2 d z vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
c9 a vss 0.610f
c8 b vss 0.677f
c6 c vss 0.603f
c5 d vss 0.638f
c1 z vss 0.948f
.ends
.subckt nand3 a b c vdd vss z
m01 vdd a z vdd pmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m02 vss a sig2 vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m03 z b vdd vdd pmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m04 sig2 b sig3 vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m05 vdd c z vdd pmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m06 sig3 c z vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
c5 a vss 0.491f
c6 b vss 0.400f
c7 c vss 0.478f
c1 z vss 0.850f
.ends
.subckt nand2 a b vdd vss z
m01 vdd a z vdd pmos l=0.12u w=0.77u as=0.20405p ad=0.20405p ps=2.07u pd=2.07u
m02 vss a sig3 vss nmos l=0.12u w=0.66u as=0.1749p ad=0.1749p ps=1.85u pd=1.85u
m03 z b vdd vdd pmos l=0.12u w=0.77u as=0.20405p ad=0.20405p ps=2.07u pd=2.07u
m04 sig3 b z vss nmos l=0.12u w=0.66u as=0.1749p ad=0.1749p ps=1.85u pd=1.85u
c4 a vss 0.549f
c5 b vss 0.578f
c1 z vss 0.609f
.ends
.subckt and2 a b vdd vss z
m01 06 a vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m02 n1 a vss vss nmos l=0.12u w=0.605u as=0.160325p ad=0.160325p ps=1.74u pd=1.74u
m03 vdd b 06 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m04 06 b n1 vss nmos l=0.12u w=0.605u as=0.160325p ad=0.160325p ps=1.74u pd=1.74u
m05 vdd 06 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m06 vss 06 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 06 vss 0.724f
c5 a vss 0.663f
c6 b vss 0.538f
c3 z vss 0.595f
.ends
* simulation command:
.tran 1ps 1ns
.print tran V(g430) V(g426) V(g429) V(g431) V(g428) V(g427) V(g432)
.end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,793 @@
* ISCAS85 benchmark circuit SPICE netlist
* generated by spicegen.pl 1.0
* by Jingye Xu @ VLSI group, Dept of ECE, UIC
.INCLUDE ../../technology/45nm_HP.pm
.OPTIONS GMIN=1e-015 ABSTOL=1e-13 ACCT
* the voltage souces:
Vdd vdd gnd DC 1.8
* the input voltage sources
V1 g21 gnd pulse(0 1 0p 200p 200p 1n 2n)
V2 g18 gnd pulse(0 1 0p 200p 200p 1n 2n)
V3 g31 gnd pulse(0 1 0p 200p 200p 1n 2n)
V4 g17 gnd pulse(0 1 0p 200p 200p 1n 2n)
V5 g27 gnd pulse(0 1 0p 200p 200p 1n 2n)
V6 g11 gnd pulse(0 1 0p 200p 200p 1n 2n)
V7 g22 gnd pulse(0 1 0p 200p 200p 1n 2n)
V8 g32 gnd pulse(0 1 0p 200p 200p 1n 2n)
V9 g30 gnd pulse(0 1 0p 200p 200p 1n 2n)
V10 g4 gnd pulse(0 1 0p 200p 200p 1n 2n)
V11 g12 gnd pulse(0 1 0p 200p 200p 1n 2n)
V12 g29 gnd pulse(0 1 0p 200p 200p 1n 2n)
V13 g24 gnd pulse(0 1 0p 200p 200p 1n 2n)
V14 g39 gnd pulse(0 1 0p 200p 200p 1n 2n)
V15 g38 gnd pulse(0 1 0p 200p 200p 1n 2n)
V16 g20 gnd pulse(0 1 0p 200p 200p 1n 2n)
V17 g5 gnd pulse(0 1 0p 200p 200p 1n 2n)
V18 g35 gnd pulse(0 1 0p 200p 200p 1n 2n)
V19 g23 gnd pulse(0 1 0p 200p 200p 1n 2n)
V20 g13 gnd pulse(0 1 0p 200p 200p 1n 2n)
V21 g2 gnd pulse(0 1 0p 200p 200p 1n 2n)
V22 g37 gnd pulse(0 1 0p 200p 200p 1n 2n)
V23 g41 gnd pulse(0 1 0p 200p 200p 1n 2n)
V24 g9 gnd pulse(0 1 0p 200p 200p 1n 2n)
V25 g40 gnd pulse(0 1 0p 200p 200p 1n 2n)
V26 g14 gnd pulse(0 1 0p 200p 200p 1n 2n)
V27 g36 gnd pulse(0 1 0p 200p 200p 1n 2n)
V28 g19 gnd pulse(0 1 0p 200p 200p 1n 2n)
V29 g8 gnd pulse(0 1 0p 200p 200p 1n 2n)
V30 g3 gnd pulse(0 1 0p 200p 200p 1n 2n)
V31 g26 gnd pulse(0 1 0p 200p 200p 1n 2n)
V32 g16 gnd pulse(0 1 0p 200p 200p 1n 2n)
V33 g10 gnd pulse(0 1 0p 200p 200p 1n 2n)
V34 g6 gnd pulse(0 1 0p 200p 200p 1n 2n)
V35 g1 gnd pulse(0 1 0p 200p 200p 1n 2n)
V36 g28 gnd pulse(0 1 0p 200p 200p 1n 2n)
V37 g25 gnd pulse(0 1 0p 200p 200p 1n 2n)
V38 g15 gnd pulse(0 1 0p 200p 200p 1n 2n)
V39 g33 gnd pulse(0 1 0p 200p 200p 1n 2n)
V40 g7 gnd pulse(0 1 0p 200p 200p 1n 2n)
V41 g34 gnd pulse(0 1 0p 200p 200p 1n 2n)
X101 g2 z172 vdd gnd x172 nand2
X366 g217 z325 vdd gnd x325 nand2
X615 g29 vdd gnd w496 not1
X467 g286 g426 vdd gnd g460 and2
X194 g156 vdd gnd w201 not1
X2 g2 vdd gnd z146 not1
X505 g7 vdd gnd w474 not1
X254 g192 vdd gnd w219 not1
X629 x498 y498 vdd gnd g498 nand2
X575 g21 vdd gnd w488 not1
X428 g356 g299 g357 vdd gnd x41 and3
X234 g180 vdd gnd w215 not1
X414 g361 g362 g312 g363 vdd gnd g383 and4
X285 g207 vdd gnd z225 not1
X130 g21 vdd gnd z178 not1
X144 g26 vdd gnd w181 not1
X591 g459 vdd gnd z491 not1
X159 g20 vdd gnd w184 not1
X120 g8 vdd gnd z176 not1
X31 g13 vdd gnd w152 not1
X554 x483 y483 vdd gnd g483 nand2
X314 g167 vdd gnd w231 not1
X189 g154 vdd gnd w198 not1
X578 g456 w488 vdd gnd y488 nand2
X518 g444 w476 vdd gnd y476 nand2
X471 g286 g431 vdd gnd g464 and2
X504 x473 y473 vdd gnd g473 nand2
X584 x489 y489 vdd gnd g489 nand2
X302 g224 w228 vdd gnd y228 nand2
X526 g446 vdd gnd z478 not1
X328 x233 y233 vdd gnd g233 nand2
X202 g159 w204 vdd gnd y204 nand2
X170 g147 vdd gnd z186 not1
X415 g364 g299 g365 g366 vdd gnd g384 and4
X597 g25 z492 vdd gnd x492 nand2
X61 g25 vdd gnd w158 not1
X377 g273 vdd gnd g346 not1
X439 x71 x72 vdd gnd g426 and2
X293 x226 y226 vdd gnd g226 nand2
X89 g1 vdd gnd w170 not1
X275 g207 vdd gnd z223 not1
X280 g204 vdd gnd z224 not1
X523 g445 w477 vdd gnd y477 nand2
X246 g184 z217 vdd gnd x217 nand2
X325 g221 vdd gnd z233 not1
X67 g28 vdd gnd z159 not1
X558 g452 w484 vdd gnd y484 nand2
X543 g449 w481 vdd gnd y481 nand2
X398 g299 vdd gnd g367 not1
X218 x211 y211 vdd gnd g211 nand2
X46 g19 vdd gnd w155 not1
X228 x213 y213 vdd gnd g213 nand2
X15 x148 y148 vdd gnd g148 nand2
X58 g23 z157 vdd gnd x157 nand2
X374 g273 vdd gnd g343 not1
X113 x174 y174 vdd gnd g174 nand2
X396 g312 vdd gnd g365 not1
X125 g16 vdd gnd z177 not1
X5 x146 y146 vdd gnd g146 nand2
X383 g299 vdd gnd g352 not1
X308 x229 y229 vdd gnd g229 nand2
X40 x153 y153 vdd gnd g153 nand2
X586 g458 vdd gnd z490 not1
X457 g260 g411 vdd gnd g450 and2
X260 g192 vdd gnd z220 not1
X214 g172 vdd gnd w211 not1
X79 g32 w161 vdd gnd y161 nand2
X182 g151 w192 vdd gnd y192 nand2
X139 g18 vdd gnd w180 not1
X420 g351 g386 vdd gnd x12 and2
X633 g467 w499 vdd gnd y499 nand2
X266 g189 z221 vdd gnd x221 nand2
X564 x485 y485 vdd gnd g485 nand2
X358 x299 y299 vdd gnd g299 nand2
X585 g23 vdd gnd w490 not1
X283 x224 y224 vdd gnd g224 nand2
X365 g233 vdd gnd z325 not1
X268 x221 y221 vdd gnd g221 nand2
X596 g460 vdd gnd z492 not1
X622 g30 z497 vdd gnd x497 nand2
X614 x495 y495 vdd gnd g495 nand2
X551 g451 vdd gnd z483 not1
X470 g325 g426 vdd gnd g463 and2
X185 g153 vdd gnd z195 not1
X44 g18 w154 vdd gnd y154 nand2
X86 g38 g41 vdd gnd g167 and2
X14 g6 w148 vdd gnd y148 nand2
X438 g375 g391 vdd gnd x72 and2
X73 g29 z160 vdd gnd x160 nand2
X30 x151 y151 vdd gnd g151 nand2
X94 g9 vdd gnd w171 not1
X62 g26 vdd gnd z158 not1
X417 g378 g379 g380 g381 vdd gnd g386 or4
X121 g4 z176 vdd gnd x176 nand2
X57 g24 vdd gnd z157 not1
X609 x494 y494 vdd gnd g494 nand2
X136 g25 z179 vdd gnd x179 nand2
X506 g442 vdd gnd z474 not1
X66 g27 vdd gnd w159 not1
X632 g32 z499 vdd gnd x499 nand2
X599 x492 y492 vdd gnd g492 nand2
X368 x325 y325 vdd gnd g325 nand2
X236 g180 z215 vdd gnd x215 nand2
X624 x497 y497 vdd gnd g497 nand2
X233 x214 y214 vdd gnd g214 nand2
X590 g24 vdd gnd w491 not1
X569 x486 y486 vdd gnd g486 nand2
X525 g11 vdd gnd w478 not1
X290 g222 vdd gnd z226 not1
X473 g312 g431 vdd gnd g466 and2
X95 g13 vdd gnd z171 not1
X503 g441 w473 vdd gnd y473 nand2
X480 g2 vdd gnd w469 not1
X442 x81 x82 vdd gnd g431 and2
X47 g20 vdd gnd z155 not1
X179 g150 vdd gnd w192 not1
X276 g204 z223 vdd gnd x223 nand2
X345 g229 vdd gnd z273 not1
X197 g157 w201 vdd gnd y201 nand2
X495 g5 vdd gnd w472 not1
X430 x41 x42 vdd gnd g411 and2
X153 x182 y182 vdd gnd g182 nand2
X81 g33 g41 vdd gnd g162 and2
X315 g219 vdd gnd z231 not1
X371 g260 vdd gnd g340 not1
X529 x478 y478 vdd gnd g478 nand2
X397 g325 vdd gnd g366 not1
X143 x180 y180 vdd gnd g180 nand2
X309 g166 vdd gnd w230 not1
X78 g31 z161 vdd gnd x161 nand2
X406 g273 vdd gnd g375 not1
X56 g23 vdd gnd w157 not1
X20 x149 y149 vdd gnd g149 nand2
X384 g312 vdd gnd g353 not1
X209 g170 vdd gnd w210 not1
X423 g325 g386 vdd gnd x22 and2
X100 g6 vdd gnd z172 not1
X510 g8 vdd gnd w475 not1
X464 g299 g421 vdd gnd g457 and2
X201 g158 z204 vdd gnd x204 nand2
X537 g13 z480 vdd gnd x480 nand2
X265 g195 vdd gnd z221 not1
X429 g325 g386 vdd gnd x42 and2
X245 g185 vdd gnd z217 not1
X603 g461 w493 vdd gnd y493 nand2
X517 g9 z476 vdd gnd x476 nand2
X138 x179 y179 vdd gnd g179 nand2
X27 g12 vdd gnd z151 not1
X577 g21 z488 vdd gnd x488 nand2
X301 g164 z228 vdd gnd x228 nand2
X114 g11 vdd gnd w175 not1
X122 g8 w176 vdd gnd y176 nand2
X102 g6 w172 vdd gnd y172 nand2
X494 x471 y471 vdd gnd g471 nand2
X4 g2 w146 vdd gnd y146 nand2
X219 g174 vdd gnd w212 not1
X296 g163 z227 vdd gnd x227 nand2
X230 g179 vdd gnd z214 not1
X213 x210 y210 vdd gnd g210 nand2
X400 g325 vdd gnd g369 not1
X200 g159 vdd gnd z204 not1
X108 x173 y173 vdd gnd g173 nand2
X444 g247 g396 vdd gnd g437 and2
X522 g10 z477 vdd gnd x477 nand2
X156 g27 z183 vdd gnd x183 nand2
X612 g28 z495 vdd gnd x495 nand2
X351 g214 z286 vdd gnd x286 nand2
X412 g234 g347 g348 g349 vdd gnd g381 and4
X132 g21 w178 vdd gnd y178 nand2
X631 g467 vdd gnd z499 not1
X437 g374 g247 g260 vdd gnd x71 and3
X180 g151 vdd gnd z192 not1
X141 g18 z180 vdd gnd x180 nand2
X41 g17 vdd gnd w154 not1
X618 g464 w496 vdd gnd y496 nand2
X278 x223 y223 vdd gnd g223 nand2
X295 g223 vdd gnd z227 not1
X13 g5 z148 vdd gnd x148 nand2
X37 g16 vdd gnd z153 not1
X382 g325 vdd gnd g351 not1
X252 g189 w218 vdd gnd y218 nand2
X552 g16 z483 vdd gnd x483 nand2
X240 g183 vdd gnd z216 not1
X107 g14 w173 vdd gnd y173 nand2
X608 g462 w494 vdd gnd y494 nand2
X481 g437 vdd gnd z469 not1
X544 x481 y481 vdd gnd g481 nand2
X164 g28 vdd gnd w185 not1
X60 x157 y157 vdd gnd g157 nand2
X247 g185 w217 vdd gnd y217 nand2
X469 g312 g426 vdd gnd g462 and2
X524 x477 y477 vdd gnd g477 nand2
X49 g20 w155 vdd gnd y155 nand2
X264 g189 vdd gnd w221 not1
X443 g234 g396 vdd gnd g436 and2
X241 g182 z216 vdd gnd x216 nand2
X279 g198 vdd gnd w224 not1
X375 g234 vdd gnd g344 not1
X326 g169 z233 vdd gnd x233 nand2
X39 g16 w153 vdd gnd y153 nand2
X116 g11 z175 vdd gnd x175 nand2
X225 g177 vdd gnd z213 not1
X566 g454 vdd gnd z486 not1
X172 g147 w186 vdd gnd y186 nand2
X426 g355 g386 vdd gnd x32 and2
X93 x170 y170 vdd gnd g170 nand2
X465 g312 g421 vdd gnd g458 and2
X344 g213 vdd gnd w273 not1
X29 g12 w151 vdd gnd y151 nand2
X9 g4 w147 vdd gnd y147 nand2
X157 g31 w183 vdd gnd y183 nand2
X323 x232 y232 vdd gnd g232 nand2
X284 g201 vdd gnd w225 not1
X300 g224 vdd gnd z228 not1
X546 g450 vdd gnd z482 not1
X74 g30 w160 vdd gnd y160 nand2
X594 x491 y491 vdd gnd g491 nand2
X488 g438 w470 vdd gnd y470 nand2
X574 x487 y487 vdd gnd g487 nand2
X316 g167 z231 vdd gnd x231 nand2
X472 g299 g431 vdd gnd g465 and2
X51 g21 vdd gnd w156 not1
X557 g17 z484 vdd gnd x484 nand2
X69 g28 w159 vdd gnd y159 nand2
X408 g260 vdd gnd g377 not1
X634 x499 y499 vdd gnd g499 nand2
X208 x207 y207 vdd gnd g207 nand2
X431 g234 g370 g260 vdd gnd x51 and3
X154 g27 vdd gnd w183 not1
X390 g299 vdd gnd g359 not1
X493 g439 w471 vdd gnd y471 nand2
X332 g226 w234 vdd gnd y234 nand2
X210 g171 vdd gnd z210 not1
X381 g299 vdd gnd g350 not1
X256 g192 z219 vdd gnd x219 nand2
X177 g149 w189 vdd gnd y189 nand2
X387 g286 vdd gnd g356 not1
X196 g156 z201 vdd gnd x201 nand2
X576 g456 vdd gnd z488 not1
X498 g440 w472 vdd gnd y472 nand2
X621 g465 vdd gnd z497 not1
X287 g207 w225 vdd gnd y225 nand2
X59 g24 w157 vdd gnd y157 nand2
X451 g234 g406 vdd gnd g444 and2
X625 g31 vdd gnd w498 not1
X579 x488 y488 vdd gnd g488 nand2
X450 g273 g401 vdd gnd g443 and2
X68 g27 z159 vdd gnd x159 nand2
X92 g5 w170 vdd gnd y170 nand2
X131 g17 z178 vdd gnd x178 nand2
X401 g247 vdd gnd g370 not1
X422 g286 g352 g353 vdd gnd x21 and3
X445 g260 g396 vdd gnd g438 and2
X337 g227 w247 vdd gnd y247 nand2
X616 g464 vdd gnd z496 not1
X255 g195 vdd gnd z219 not1
X352 g230 w286 vdd gnd y286 nand2
X342 g228 w260 vdd gnd y260 nand2
X48 g19 z155 vdd gnd x155 nand2
X475 g1 vdd gnd w468 not1
X212 g171 w210 vdd gnd y210 nand2
X38 g15 z153 vdd gnd x153 nand2
X75 x160 y160 vdd gnd g160 nand2
X363 x312 y312 vdd gnd g312 nand2
X21 g9 vdd gnd w150 not1
X8 g3 z147 vdd gnd x147 nand2
X80 x161 y161 vdd gnd g161 nand2
X3 g1 z146 vdd gnd x146 nand2
X292 g222 w226 vdd gnd y226 nand2
X198 x201 y201 vdd gnd g201 nand2
X12 g6 vdd gnd z148 not1
X413 g358 g359 g360 g325 vdd gnd g382 and4
X373 g247 vdd gnd g342 not1
X253 x218 y218 vdd gnd g218 nand2
X360 g232 vdd gnd z312 not1
X391 g312 vdd gnd g360 not1
X123 x176 y176 vdd gnd g176 nand2
X183 x192 y192 vdd gnd g192 nand2
X188 x195 y195 vdd gnd g195 nand2
X330 g226 vdd gnd z234 not1
X399 g312 vdd gnd g368 not1
X617 g29 z496 vdd gnd x496 nand2
X378 g247 vdd gnd g347 not1
X462 g325 g416 vdd gnd g455 and2
X339 g212 vdd gnd w260 not1
X545 g15 vdd gnd w482 not1
X281 g198 z224 vdd gnd x224 nand2
X211 g170 z210 vdd gnd x210 nand2
X171 g146 z186 vdd gnd x186 nand2
X409 g338 g339 g340 g273 vdd gnd g378 and4
X191 g154 z198 vdd gnd x198 nand2
X150 g23 vdd gnd z182 not1
X427 x31 x32 vdd gnd g406 and2
X514 x475 y475 vdd gnd g475 nand2
X468 g299 g426 vdd gnd g461 and2
X317 g219 w231 vdd gnd y231 nand2
X88 g40 g41 vdd gnd g169 and2
X235 g181 vdd gnd z215 not1
X207 g161 w207 vdd gnd y207 nand2
X343 x260 y260 vdd gnd g260 nand2
X124 g12 vdd gnd w177 not1
X178 x189 y189 vdd gnd g189 nand2
X519 x476 y476 vdd gnd g476 nand2
X482 g2 z469 vdd gnd x469 nand2
X226 g176 z213 vdd gnd x213 nand2
X306 g165 z229 vdd gnd x229 nand2
X238 x215 y215 vdd gnd g215 nand2
X565 g19 vdd gnd w486 not1
X263 x220 y220 vdd gnd g220 nand2
X158 x183 y183 vdd gnd g183 nand2
X319 g168 vdd gnd w232 not1
X36 g15 vdd gnd w153 not1
X436 x61 x62 vdd gnd g421 and2
X489 x470 y470 vdd gnd g470 nand2
X199 g158 vdd gnd w204 not1
X388 g312 vdd gnd g357 not1
X410 g341 g342 g260 g343 vdd gnd g379 and4
X605 g27 vdd gnd w494 not1
X338 x247 y247 vdd gnd g247 nand2
X261 g186 z220 vdd gnd x220 nand2
X35 x152 y152 vdd gnd g152 nand2
X215 g173 vdd gnd z211 not1
X322 g220 w232 vdd gnd y232 nand2
X453 g260 g406 vdd gnd g446 and2
X96 g9 z171 vdd gnd x171 nand2
X600 g26 vdd gnd w493 not1
X446 g273 g396 vdd gnd g439 and2
X70 x159 y159 vdd gnd g159 nand2
X500 g6 vdd gnd w473 not1
X535 g13 vdd gnd w480 not1
X589 x490 y490 vdd gnd g490 nand2
X324 g169 vdd gnd w233 not1
X369 g234 vdd gnd g338 not1
X626 g466 vdd gnd z498 not1
X492 g4 z471 vdd gnd x471 nand2
X299 g164 vdd gnd w228 not1
X559 x484 y484 vdd gnd g484 nand2
X539 x480 y480 vdd gnd g480 nand2
X389 g286 vdd gnd g358 not1
X305 g225 vdd gnd z229 not1
X611 g463 vdd gnd z495 not1
X1 g1 vdd gnd w146 not1
X105 g14 vdd gnd z173 not1
X353 x286 y286 vdd gnd g286 nand2
X206 g160 z207 vdd gnd x207 nand2
X229 g178 vdd gnd w214 not1
X572 g20 z487 vdd gnd x487 nand2
X509 x474 y474 vdd gnd g474 nand2
X186 g152 z195 vdd gnd x195 nand2
X549 x482 y482 vdd gnd g482 nand2
X163 x184 y184 vdd gnd g184 nand2
X392 g286 vdd gnd g361 not1
X531 g447 vdd gnd z479 not1
X329 g210 vdd gnd w234 not1
X402 g273 vdd gnd g371 not1
X483 g437 w469 vdd gnd y469 nand2
X269 g198 vdd gnd w222 not1
X628 g466 w498 vdd gnd y498 nand2
X117 g15 w175 vdd gnd y175 nand2
X341 g212 z260 vdd gnd x260 nand2
X592 g24 z491 vdd gnd x491 nand2
X223 x212 y212 vdd gnd g212 nand2
X129 g17 vdd gnd w178 not1
X550 g16 vdd gnd w483 not1
X76 g31 vdd gnd w161 not1
X23 g9 z150 vdd gnd x150 nand2
X271 g198 z222 vdd gnd x222 nand2
X311 g166 z230 vdd gnd x230 nand2
X555 g17 vdd gnd w484 not1
X82 g34 g41 vdd gnd g163 and2
X259 g186 vdd gnd w220 not1
X289 g162 vdd gnd w226 not1
X441 g273 g391 vdd gnd x82 and2
X165 g32 vdd gnd z185 not1
X318 x231 y231 vdd gnd g231 nand2
X42 g18 vdd gnd z154 not1
X155 g31 vdd gnd z183 not1
X243 x216 y216 vdd gnd g216 nand2
X435 g273 g391 vdd gnd x62 and2
X133 x178 y178 vdd gnd g178 nand2
X619 x496 y496 vdd gnd g496 nand2
X91 g1 z170 vdd gnd x170 nand2
X258 x219 y219 vdd gnd g219 nand2
X474 g325 g431 vdd gnd g467 and2
X237 g181 w215 vdd gnd y215 nand2
X347 g229 w273 vdd gnd y273 nand2
X548 g450 w482 vdd gnd y482 nand2
X567 g19 z486 vdd gnd x486 nand2
X174 g148 vdd gnd w189 not1
X424 x21 x22 vdd gnd g401 and2
X606 g462 vdd gnd z494 not1
X491 g439 vdd gnd z471 not1
X115 g15 vdd gnd z175 not1
X10 x147 y147 vdd gnd g147 nand2
X582 g22 z489 vdd gnd x489 nand2
X521 g445 vdd gnd z477 not1
X181 g150 z192 vdd gnd x192 nand2
X257 g195 w219 vdd gnd y219 nand2
X34 g14 w152 vdd gnd y152 nand2
X77 g32 vdd gnd z161 not1
X249 g186 vdd gnd w218 not1
X540 g14 vdd gnd w481 not1
X33 g13 z152 vdd gnd x152 nand2
X128 x177 y177 vdd gnd g177 nand2
X610 g28 vdd gnd w495 not1
X166 g28 z185 vdd gnd x185 nand2
X248 x217 y217 vdd gnd g217 nand2
X562 g18 z485 vdd gnd x485 nand2
X142 g22 w180 vdd gnd y180 nand2
X168 x185 y185 vdd gnd g185 nand2
X224 g176 vdd gnd w213 not1
X277 g207 w223 vdd gnd y223 nand2
X106 g10 z173 vdd gnd x173 nand2
X118 x175 y175 vdd gnd g175 nand2
X354 g215 vdd gnd w299 not1
X149 g19 vdd gnd w182 not1
X90 g5 vdd gnd z170 not1
X335 g227 vdd gnd z247 not1
X376 g260 vdd gnd g345 not1
X623 g465 w497 vdd gnd y497 nand2
X393 g299 vdd gnd g362 not1
X251 g186 z218 vdd gnd x218 nand2
X570 g20 vdd gnd w487 not1
X530 g12 vdd gnd w479 not1
X607 g27 z494 vdd gnd x494 nand2
X83 g35 g41 vdd gnd g164 and2
X463 g286 g421 vdd gnd g456 and2
X321 g168 z232 vdd gnd x232 nand2
X270 g201 vdd gnd z222 not1
X286 g201 z225 vdd gnd x225 nand2
X547 g15 z482 vdd gnd x482 nand2
X458 g273 g411 vdd gnd g451 and2
X22 g10 vdd gnd z150 not1
X147 g30 w181 vdd gnd y181 nand2
X340 g228 vdd gnd z260 not1
X43 g17 z154 vdd gnd x154 nand2
X418 g382 g383 g384 g385 vdd gnd g391 or4
X310 g218 vdd gnd z230 not1
X459 g286 g416 vdd gnd g452 and2
X411 g344 g247 g345 g346 vdd gnd g380 and4
X193 x198 y198 vdd gnd g198 nand2
X380 g273 vdd gnd g349 not1
X242 g183 w216 vdd gnd y216 nand2
X111 g3 z174 vdd gnd x174 nand2
X513 g443 w475 vdd gnd y475 nand2
X477 g1 z468 vdd gnd x468 nand2
X28 g11 z151 vdd gnd x151 nand2
X536 g448 vdd gnd z480 not1
X573 g455 w487 vdd gnd y487 nand2
X50 x155 y155 vdd gnd g155 nand2
X152 g23 w182 vdd gnd y182 nand2
X568 g454 w486 vdd gnd y486 nand2
X499 x472 y472 vdd gnd g472 nand2
X440 g376 g247 g377 vdd gnd x81 and3
X205 g161 vdd gnd z207 not1
X294 g163 vdd gnd w227 not1
X52 g22 vdd gnd z156 not1
X173 x186 y186 vdd gnd g186 nand2
X272 g201 w222 vdd gnd y222 nand2
X452 g247 g406 vdd gnd g445 and2
X476 g436 vdd gnd z468 not1
X484 x469 y469 vdd gnd g469 nand2
X447 g234 g401 vdd gnd g440 and2
X448 g247 g401 vdd gnd g441 and2
X331 g210 z234 vdd gnd x234 nand2
X348 x273 y273 vdd gnd g273 nand2
X627 g31 z498 vdd gnd x498 nand2
X595 g25 vdd gnd w492 not1
X520 g10 vdd gnd w477 not1
X162 g24 w184 vdd gnd y184 nand2
X355 g231 vdd gnd z299 not1
X364 g217 vdd gnd w325 not1
X403 g247 vdd gnd g372 not1
X385 g286 vdd gnd g354 not1
X320 g220 vdd gnd z232 not1
X87 g39 g41 vdd gnd g168 and2
X356 g215 z299 vdd gnd x299 nand2
X184 g152 vdd gnd w195 not1
X507 g7 z474 vdd gnd x474 nand2
X359 g216 vdd gnd w312 not1
X135 g29 vdd gnd z179 not1
X63 g25 z158 vdd gnd x158 nand2
X282 g204 w224 vdd gnd y224 nand2
X333 x234 y234 vdd gnd g234 nand2
X291 g162 z226 vdd gnd x226 nand2
X167 g32 w185 vdd gnd y185 nand2
X563 g453 w485 vdd gnd y485 nand2
X455 g234 g411 vdd gnd g448 and2
X556 g452 vdd gnd z484 not1
X460 g299 g416 vdd gnd g453 and2
X103 x172 y172 vdd gnd g172 nand2
X593 g459 w491 vdd gnd y491 nand2
X239 g182 vdd gnd w216 not1
X434 g234 g372 g373 vdd gnd x61 and3
X145 g30 vdd gnd z181 not1
X16 g7 vdd gnd w149 not1
X602 g26 z493 vdd gnd x493 nand2
X598 g460 w492 vdd gnd y492 nand2
X312 g218 w230 vdd gnd y230 nand2
X487 g3 z470 vdd gnd x470 nand2
X583 g457 w489 vdd gnd y489 nand2
X497 g5 z472 vdd gnd x472 nand2
X65 x158 y158 vdd gnd g158 nand2
X407 g234 vdd gnd g376 not1
X425 g354 g299 g312 vdd gnd x31 and3
X127 g16 w177 vdd gnd y177 nand2
X72 g30 vdd gnd z160 not1
X404 g260 vdd gnd g373 not1
X288 x225 y225 vdd gnd g225 nand2
X386 g325 vdd gnd g355 not1
X516 g444 vdd gnd z476 not1
X533 g447 w479 vdd gnd y479 nand2
X112 g7 w174 vdd gnd y174 nand2
X303 x228 y228 vdd gnd g228 nand2
X541 g449 vdd gnd z481 not1
X304 g165 vdd gnd w229 not1
X313 x230 y230 vdd gnd g230 nand2
X137 g29 w179 vdd gnd y179 nand2
X588 g458 w490 vdd gnd y490 nand2
X327 g221 w233 vdd gnd y233 nand2
X532 g12 z479 vdd gnd x479 nand2
X478 g436 w468 vdd gnd y468 nand2
X146 g26 z181 vdd gnd x181 nand2
X511 g443 vdd gnd z475 not1
X55 x156 y156 vdd gnd g156 nand2
X25 x150 y150 vdd gnd g150 nand2
X84 g36 g41 vdd gnd g165 and2
X19 g8 w149 vdd gnd y149 nand2
X367 g233 w325 vdd gnd y325 nand2
X273 x222 y222 vdd gnd g222 nand2
X372 g234 vdd gnd g341 not1
X394 g325 vdd gnd g363 not1
X349 g214 vdd gnd w286 not1
X161 g20 z184 vdd gnd x184 nand2
X490 g4 vdd gnd w471 not1
X528 g446 w478 vdd gnd y478 nand2
X538 g448 w480 vdd gnd y480 nand2
X160 g24 vdd gnd z184 not1
X190 g155 vdd gnd z198 not1
X449 g260 g401 vdd gnd g442 and2
X336 g211 z247 vdd gnd x247 nand2
X297 g223 w227 vdd gnd y227 nand2
X613 g463 w495 vdd gnd y495 nand2
X502 g6 z473 vdd gnd x473 nand2
X553 g451 w483 vdd gnd y483 nand2
X7 g4 vdd gnd z147 not1
X560 g18 vdd gnd w485 not1
X216 g172 z211 vdd gnd x211 nand2
X176 g148 z189 vdd gnd x189 nand2
X98 x171 y171 vdd gnd g171 nand2
X204 g160 vdd gnd w207 not1
X221 g174 z212 vdd gnd x212 nand2
X232 g179 w214 vdd gnd y214 nand2
X604 x493 y493 vdd gnd g493 nand2
X26 g11 vdd gnd w151 not1
X54 g22 w156 vdd gnd y156 nand2
X244 g184 vdd gnd w217 not1
X262 g192 w220 vdd gnd y220 nand2
X18 g7 z149 vdd gnd x149 nand2
X419 g286 g350 g312 vdd gnd x11 and3
X298 x227 y227 vdd gnd g227 nand2
X461 g312 g416 vdd gnd g454 and2
X126 g12 z177 vdd gnd x177 nand2
X203 x204 y204 vdd gnd g204 nand2
X433 x51 x52 vdd gnd g416 and2
X220 g175 vdd gnd z212 not1
X110 g7 vdd gnd z174 not1
X362 g232 w312 vdd gnd y312 nand2
X379 g260 vdd gnd g348 not1
X53 g21 z156 vdd gnd x156 nand2
X346 g213 z273 vdd gnd x273 nand2
X496 g440 vdd gnd z472 not1
X501 g441 vdd gnd z473 not1
X134 g25 vdd gnd w179 not1
X17 g8 vdd gnd z149 not1
X587 g23 z490 vdd gnd x490 nand2
X187 g153 w195 vdd gnd y195 nand2
X334 g211 vdd gnd w247 not1
X485 g3 vdd gnd w470 not1
X6 g3 vdd gnd w147 not1
X64 g26 w158 vdd gnd y158 nand2
X109 g3 vdd gnd w174 not1
X97 g13 w171 vdd gnd y171 nand2
X32 g14 vdd gnd z152 not1
X192 g155 w198 vdd gnd y198 nand2
X405 g234 vdd gnd g374 not1
X71 g29 vdd gnd w160 not1
X140 g22 vdd gnd z180 not1
X148 x181 y181 vdd gnd g181 nand2
X274 g204 vdd gnd w223 not1
X222 g175 w212 vdd gnd y212 nand2
X534 x479 y479 vdd gnd g479 nand2
X466 g325 g421 vdd gnd g459 and2
X620 g30 vdd gnd w497 not1
X432 g371 g391 vdd gnd x52 and2
X24 g10 w150 vdd gnd y150 nand2
X515 g9 vdd gnd w476 not1
X151 g19 z182 vdd gnd x182 nand2
X227 g177 w213 vdd gnd y213 nand2
X486 g438 vdd gnd z470 not1
X85 g37 g41 vdd gnd g166 and2
X267 g195 w221 vdd gnd y221 nand2
X581 g457 vdd gnd z489 not1
X370 g247 vdd gnd g339 not1
X169 g146 vdd gnd w186 not1
X11 g5 vdd gnd w148 not1
X350 g230 vdd gnd z286 not1
X456 g247 g411 vdd gnd g449 and2
X217 g173 w211 vdd gnd y211 nand2
X307 g225 w229 vdd gnd y229 nand2
X542 g14 z481 vdd gnd x481 nand2
X580 g22 vdd gnd w489 not1
X527 g11 z478 vdd gnd x478 nand2
X250 g189 vdd gnd z218 not1
X601 g461 vdd gnd z493 not1
X195 g157 vdd gnd z201 not1
X421 x11 x12 vdd gnd g396 and2
X357 g231 w299 vdd gnd y299 nand2
X571 g455 vdd gnd z487 not1
X119 g4 vdd gnd w176 not1
X99 g2 vdd gnd w172 not1
X45 x154 y154 vdd gnd g154 nand2
X454 g273 g406 vdd gnd g447 and2
X630 g32 vdd gnd w499 not1
X508 g442 w474 vdd gnd y474 nand2
X512 g8 z475 vdd gnd x475 nand2
X231 g178 z214 vdd gnd x214 nand2
X175 g149 vdd gnd z189 not1
X479 x468 y468 vdd gnd g468 nand2
X395 g286 vdd gnd g364 not1
X104 g10 vdd gnd w173 not1
X416 g286 g367 g368 g369 vdd gnd g385 and4
X361 g216 z312 vdd gnd x312 nand2
X561 g453 vdd gnd z485 not1
.subckt and3 a b c vdd vss z
m01 08 a vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m02 n1 a vss vss nmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m03 vdd b 08 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m04 sig6 b n1 vss nmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m05 08 c vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m06 08 c sig6 vss nmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m07 vdd 08 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m08 vss 08 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 08 vss 1.142f
c5 a vss 0.539f
c7 b vss 0.609f
c8 c vss 0.651f
c3 z vss 0.745f
.ends
.subckt or4 a b c d vdd vss z
m01 sig8 a vdd vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m02 vdd a 05 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m03 sig1 a vss vss nmos l=0.12u w=0.33u as=0.08745p ad=0.08745p ps=1.19u pd=1.19u
m04 n2 b sig8 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m05 05 b 08 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m06 vss b sig1 vss nmos l=0.12u w=0.33u as=0.08745p ad=0.08745p ps=1.19u pd=1.19u
m07 10 c n2 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m08 08 c 11 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m09 sig1 c vss vss nmos l=0.12u w=0.33u as=0.08745p ad=0.08745p ps=1.19u pd=1.19u
m10 sig1 d 10 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m11 11 d sig1 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m12 vss d sig1 vss nmos l=0.12u w=0.33u as=0.08745p ad=0.08745p ps=1.19u pd=1.19u
m13 vdd sig1 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m14 vss sig1 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 a vss 1.356f
c5 b vss 1.229f
c6 c vss 1.043f
c7 d vss 0.797f
c1 sig1 vss 1.003f
c3 z vss 0.701f
.ends
.subckt xnr2v0x1 a b vdd vss z
m01 z b sig3 vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m02 bn sig3 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
m03 sig3 a vdd vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m04 vdd b bn vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m05 z bn sig3 vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
m06 vdd sig3 n1 vdd pmos l=0.12u w=1.54u as=0.4081p ad=0.4081p ps=3.61u pd=3.61u
m07 sig3 a vss vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
m08 n1 bn z vdd pmos l=0.12u w=1.54u as=0.4081p ad=0.4081p ps=3.61u pd=3.61u
m09 vss b bn vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 a vss 0.389f
c2 bn vss 1.593f
c5 b vss 0.840f
c3 sig3 vss 0.618f
c6 z vss 0.627f
.ends
.subckt nand2 a b vdd vss z
m01 vdd a z vdd pmos l=0.12u w=0.77u as=0.20405p ad=0.20405p ps=2.07u pd=2.07u
m02 vss a sig3 vss nmos l=0.12u w=0.66u as=0.1749p ad=0.1749p ps=1.85u pd=1.85u
m03 z b vdd vdd pmos l=0.12u w=0.77u as=0.20405p ad=0.20405p ps=2.07u pd=2.07u
m04 sig3 b z vss nmos l=0.12u w=0.66u as=0.1749p ad=0.1749p ps=1.85u pd=1.85u
c4 a vss 0.549f
c5 b vss 0.578f
c1 z vss 0.609f
.ends
.subckt and4 a b c d vdd vss z
m01 10 a vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m02 n1 a vss vss nmos l=0.12u w=0.88u as=0.2332p ad=0.2332p ps=2.29u pd=2.29u
m03 vdd b 10 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m04 sig7 b n1 vss nmos l=0.12u w=0.88u as=0.2332p ad=0.2332p ps=2.29u pd=2.29u
m05 10 c vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m06 n3 c sig7 vss nmos l=0.12u w=0.88u as=0.2332p ad=0.2332p ps=2.29u pd=2.29u
m07 vdd d 10 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m08 10 d n3 vss nmos l=0.12u w=0.88u as=0.2332p ad=0.2332p ps=2.29u pd=2.29u
m09 vdd 10 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m10 vss 10 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 10 vss 0.940f
c5 a vss 0.674f
c8 b vss 0.541f
c9 c vss 0.622f
c10 d vss 0.791f
c3 z vss 0.765f
.ends
.subckt and2 a b vdd vss z
m01 06 a vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m02 n1 a vss vss nmos l=0.12u w=0.605u as=0.160325p ad=0.160325p ps=1.74u pd=1.74u
m03 vdd b 06 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m04 06 b n1 vss nmos l=0.12u w=0.605u as=0.160325p ad=0.160325p ps=1.74u pd=1.74u
m05 vdd 06 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m06 vss 06 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 06 vss 0.724f
c5 a vss 0.663f
c6 b vss 0.538f
c3 z vss 0.595f
.ends
.subckt not1 a vdd vss z
m01 vdd a z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m02 vss a z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c3 a vss 0.384f
c2 z vss 0.576f
.ends
* simulation command:
.tran 1ps 1ns
.print tran V(g470) V(g483) V(g493) V(g496) V(g494) V(g484) V(g476) V(g495) V(g471) V(g489) V(g468) V(g477) V(g488) V(g478) V(g490) V(g469) V(g487) V(g491) V(g479) V(g486) V(g497) V(g498) V(g473) V(g492) V(g472) V(g485) V(g480) V(g474) V(g481) V(g475) V(g482) V(g499)
.end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,553 @@
* ISCAS85 benchmark circuit SPICE netlist
* generated by spicegen.pl 1.0
* by Jingye Xu @ VLSI group, Dept of ECE, UIC
.INCLUDE ../../technology/45nm_HP.pm
.OPTIONS GMIN=1e-015 ABSTOL=1e-13 ACCT
* the voltage souces:
Vdd vdd gnd DC 1.8
* the input voltage sources
V1 g44 gnd pulse(0 1 0p 200p 200p 1n 2n)
V2 g57 gnd pulse(0 1 0p 200p 200p 1n 2n)
V3 g35 gnd pulse(0 1 0p 200p 200p 1n 2n)
V4 g21 gnd pulse(0 1 0p 200p 200p 1n 2n)
V5 g18 gnd pulse(0 1 0p 200p 200p 1n 2n)
V6 g23 gnd pulse(0 1 0p 200p 200p 1n 2n)
V7 g13 gnd pulse(0 1 0p 200p 200p 1n 2n)
V8 g53 gnd pulse(0 1 0p 200p 200p 1n 2n)
V9 g41 gnd pulse(0 1 0p 200p 200p 1n 2n)
V10 g37 gnd pulse(0 1 0p 200p 200p 1n 2n)
V11 g2 gnd pulse(0 1 0p 200p 200p 1n 2n)
V12 g31 gnd pulse(0 1 0p 200p 200p 1n 2n)
V13 g9 gnd pulse(0 1 0p 200p 200p 1n 2n)
V14 g17 gnd pulse(0 1 0p 200p 200p 1n 2n)
V15 g27 gnd pulse(0 1 0p 200p 200p 1n 2n)
V16 g60 gnd pulse(0 1 0p 200p 200p 1n 2n)
V17 g40 gnd pulse(0 1 0p 200p 200p 1n 2n)
V18 g14 gnd pulse(0 1 0p 200p 200p 1n 2n)
V19 g47 gnd pulse(0 1 0p 200p 200p 1n 2n)
V20 g36 gnd pulse(0 1 0p 200p 200p 1n 2n)
V21 g46 gnd pulse(0 1 0p 200p 200p 1n 2n)
V22 g19 gnd pulse(0 1 0p 200p 200p 1n 2n)
V23 g58 gnd pulse(0 1 0p 200p 200p 1n 2n)
V24 g8 gnd pulse(0 1 0p 200p 200p 1n 2n)
V25 g3 gnd pulse(0 1 0p 200p 200p 1n 2n)
V26 g26 gnd pulse(0 1 0p 200p 200p 1n 2n)
V27 g59 gnd pulse(0 1 0p 200p 200p 1n 2n)
V28 g54 gnd pulse(0 1 0p 200p 200p 1n 2n)
V29 g16 gnd pulse(0 1 0p 200p 200p 1n 2n)
V30 g11 gnd pulse(0 1 0p 200p 200p 1n 2n)
V31 g22 gnd pulse(0 1 0p 200p 200p 1n 2n)
V32 g32 gnd pulse(0 1 0p 200p 200p 1n 2n)
V33 g50 gnd pulse(0 1 0p 200p 200p 1n 2n)
V34 g30 gnd pulse(0 1 0p 200p 200p 1n 2n)
V35 g10 gnd pulse(0 1 0p 200p 200p 1n 2n)
V36 g45 gnd pulse(0 1 0p 200p 200p 1n 2n)
V37 g6 gnd pulse(0 1 0p 200p 200p 1n 2n)
V38 g1 gnd pulse(0 1 0p 200p 200p 1n 2n)
V39 g48 gnd pulse(0 1 0p 200p 200p 1n 2n)
V40 g28 gnd pulse(0 1 0p 200p 200p 1n 2n)
V41 g55 gnd pulse(0 1 0p 200p 200p 1n 2n)
V42 g42 gnd pulse(0 1 0p 200p 200p 1n 2n)
V43 g51 gnd pulse(0 1 0p 200p 200p 1n 2n)
V44 g25 gnd pulse(0 1 0p 200p 200p 1n 2n)
V45 g4 gnd pulse(0 1 0p 200p 200p 1n 2n)
V46 g15 gnd pulse(0 1 0p 200p 200p 1n 2n)
V47 g12 gnd pulse(0 1 0p 200p 200p 1n 2n)
V48 g29 gnd pulse(0 1 0p 200p 200p 1n 2n)
V49 g33 gnd pulse(0 1 0p 200p 200p 1n 2n)
V50 g7 gnd pulse(0 1 0p 200p 200p 1n 2n)
V51 g49 gnd pulse(0 1 0p 200p 200p 1n 2n)
V52 g24 gnd pulse(0 1 0p 200p 200p 1n 2n)
V53 g39 gnd pulse(0 1 0p 200p 200p 1n 2n)
V54 g56 gnd pulse(0 1 0p 200p 200p 1n 2n)
V55 g52 gnd pulse(0 1 0p 200p 200p 1n 2n)
V56 g34 gnd pulse(0 1 0p 200p 200p 1n 2n)
V57 g38 gnd pulse(0 1 0p 200p 200p 1n 2n)
V58 g20 gnd pulse(0 1 0p 200p 200p 1n 2n)
V59 g5 gnd pulse(0 1 0p 200p 200p 1n 2n)
V60 g43 gnd pulse(0 1 0p 200p 200p 1n 2n)
X338 g51 g827 vdd gnd g835 and2
X101 g400 g401 vdd gnd g415 and2
X366 g354 vdd gnd g863 not1
X261 g52 g702 vdd gnd g739 and2
X194 g54 g542 vdd gnd g590 and2
X322 g51 g808 vdd gnd g819 and2
X215 g575 vdd gnd g647 not1
X35 g4 g8 vdd gnd g323 and2
X2 g1 g5 g3 g4 vdd gnd g270 nand4
X96 g382 vdd gnd g410 not1
X70 g303 g304 vdd gnd g360 nand2
X254 g682 vdd gnd g732 not1
X234 g629 g626 vdd gnd g702 and2
X285 g744 g745 vdd gnd g770 nor2
X130 g32 g445 vdd gnd g484 or2
X324 g810 g764 g697 g512 vdd gnd g821 nand4
X369 g395 vdd gnd g866 not1
X144 g29 g451 vdd gnd g498 and2
X159 g436 g47 vdd gnd g513 nand2
X120 g39 g417 vdd gnd g466 and2
X31 g4 g34 vdd gnd g317 and2
X299 g677 g779 vdd gnd g789 nor2
X314 g338 g793 vdd gnd g811 nor2
X189 g538 g41 vdd gnd g575 nand2
X305 g604 g779 vdd gnd g795 nand2
X302 g51 g786 vdd gnd g792 and2
X328 g813 g814 vdd gnd g825 nor2
X202 g554 g45 vdd gnd g613 or2
X170 g501 g502 vdd gnd g528 nor2
X1 g1 g2 g3 g4 vdd gnd g269 nand4
X61 g280 g285 vdd gnd g349 or2
X353 g846 vdd gnd g850 not1
X105 g389 g287 g10 vdd gnd g427 nand3
X377 g838 vdd gnd g874 not1
X229 g616 g511 vdd gnd g689 nor2
X206 g54 g558 vdd gnd g625 and2
X186 g529 g532 vdd gnd g572 and2
X293 g613 g756 vdd gnd g778 nand2
X89 g363 vdd gnd g403 not1
X275 g724 g725 vdd gnd g753 nor2
X163 g309 g487 vdd gnd g521 nor2
X280 g738 g746 g718 vdd gnd g761 nand3
X329 g815 g816 vdd gnd g826 nor2
X269 g620 g698 vdd gnd g747 nand2
X246 g52 g658 vdd gnd g724 and2
X117 g310 g422 vdd gnd g463 and2
X325 g811 g768 g706 g513 vdd gnd g822 nand4
X67 g22 g298 vdd gnd g355 nand2
X341 g830 vdd gnd g838 not1
X223 g600 g509 vdd gnd g671 nor2
X129 g32 g445 vdd gnd g483 nand2
X218 g582 vdd gnd g655 not1
X46 g50 g26 vdd gnd g334 and2
X228 g613 g610 vdd gnd g685 and2
X15 g11 g16 g8 vdd gnd g294 and3
X58 g276 vdd gnd g346 not1
X76 g326 g327 vdd gnd g379 nand2
X374 g646 vdd gnd g871 not1
X113 g432 g406 vdd gnd g451 nand2
X125 g369 g427 vdd gnd g475 or2
X23 g26 g27 vdd gnd g304 or2
X5 g1 g2 g9 g4 vdd gnd g279 nand4
X383 g854 vdd gnd g880 not1
X308 g723 g750 g751 g797 vdd gnd g798 nand4
X271 g594 g672 vdd gnd g749 nand2
X311 g789 g790 vdd gnd g808 nor2
X40 g45 g46 vdd gnd g328 nand2
X82 g348 g14 vdd gnd g396 and2
X289 g693 g761 vdd gnd g774 and2
X259 g53 g690 vdd gnd g737 and2
X318 g658 g802 vdd gnd g815 nor2
X260 g698 vdd gnd g738 not1
X165 g317 g491 vdd gnd g523 nor2
X214 g572 g574 vdd gnd g646 nor2
X79 g270 g343 vdd gnd g388 or2
X155 g436 g43 vdd gnd g509 and2
X42 g47 g48 vdd gnd g330 nand2
X182 g475 g527 vdd gnd g562 nand2
X243 g52 g650 vdd gnd g721 and2
X133 g24 g451 vdd gnd g487 and2
X91 g363 g366 vdd gnd g405 and2
X258 g52 g693 vdd gnd g736 and2
X139 g27 g451 vdd gnd g493 and2
X237 g639 g636 vdd gnd g712 and2
X347 g836 vdd gnd g844 not1
X266 g52 g712 vdd gnd g744 and2
X174 g518 vdd gnd g536 not1
X358 g290 vdd gnd g855 not1
X283 g739 g740 vdd gnd g768 nor2
X365 g353 vdd gnd g862 not1
X268 g629 g707 vdd gnd g746 nand2
X115 g310 g422 vdd gnd g461 and2
X10 g6 g16 g17 vdd gnd g287 and3
X257 g690 vdd gnd g735 not1
X181 g474 g526 vdd gnd g558 nand2
X77 g328 g329 vdd gnd g382 nand2
X34 g4 g8 vdd gnd g322 nor2
X185 g532 vdd gnd g571 not1
X44 g50 g24 vdd gnd g332 and2
X249 g52 g667 vdd gnd g727 and2
X86 g357 vdd gnd g400 not1
X14 g11 g16 g17 vdd gnd g293 and3
X33 g11 g40 vdd gnd g319 nand2
X128 g412 g435 vdd gnd g480 nor2
X73 g310 vdd gnd g369 not1
X30 g9 g34 vdd gnd g316 and2
X248 g663 vdd gnd g726 not1
X166 g318 g493 vdd gnd g524 nor2
X94 g379 vdd gnd g408 not1
X62 g280 g286 vdd gnd g350 or2
X121 g310 g422 vdd gnd g467 and2
X57 g276 vdd gnd g345 not1
X224 g601 vdd gnd g672 not1
X168 g497 g498 vdd gnd g526 nor2
X142 g28 g451 vdd gnd g496 and2
X277 g730 g731 vdd gnd g755 nor2
X136 g462 g463 vdd gnd g490 nor2
X106 g375 g11 g40 g389 vdd gnd g432 nand4
X66 g296 vdd gnd g354 not1
X354 g847 vdd gnd g851 not1
X118 g37 g417 vdd gnd g464 and2
X149 g32 g477 vdd gnd g503 nand2
X368 g388 vdd gnd g865 not1
X90 g366 vdd gnd g404 not1
X236 g636 vdd gnd g707 not1
X335 g720 g824 vdd gnd g832 and2
X233 g626 vdd gnd g698 not1
X376 g837 vdd gnd g873 not1
X290 g702 g765 vdd gnd g775 nor2
X251 g672 vdd gnd g729 not1
X95 g376 g379 vdd gnd g409 and2
X83 g349 vdd gnd g397 not1
X47 g50 g27 vdd gnd g335 and2
X321 g667 g805 vdd gnd g818 and2
X179 g524 g494 vdd gnd g550 nand2
X270 g620 g629 g707 vdd gnd g748 nand3
X286 g685 g756 vdd gnd g771 nor2
X276 g727 g728 vdd gnd g754 nor2
X345 g332 g834 vdd gnd g842 nor2
X197 g54 g546 vdd gnd g600 and2
X153 g436 g41 vdd gnd g507 and2
X22 g26 g27 vdd gnd g303 nand2
X81 g346 vdd gnd g395 not1
X315 g794 vdd gnd g812 not1
X147 g39 g468 vdd gnd g501 and2
X371 g398 vdd gnd g868 not1
X340 g829 vdd gnd g837 not1
X43 g47 g48 vdd gnd g331 or2
X310 g729 g795 vdd gnd g805 nand2
X143 g36 g468 vdd gnd g497 and2
X193 g542 g42 vdd gnd g585 or2
X309 g726 g749 g796 vdd gnd g802 nand3
X380 g848 vdd gnd g877 not1
X242 g647 vdd gnd g720 not1
X78 g330 g331 vdd gnd g385 nand2
X111 g402 g415 vdd gnd g445 nor2
X28 g2 g34 vdd gnd g309 and2
X56 g270 g273 vdd gnd g344 or2
X152 g480 g49 vdd gnd g506 or2
X50 g50 g29 vdd gnd g338 and2
X20 g24 g25 vdd gnd g301 nand2
X294 g778 g732 vdd gnd g779 nand2
X205 g558 g46 vdd gnd g620 or2
X209 g54 g562 vdd gnd g635 and2
X272 g585 g663 vdd gnd g750 nand2
X173 g515 vdd gnd g535 not1
X100 g396 vdd gnd g414 not1
X52 g50 g30 vdd gnd g340 and2
X201 g554 g45 vdd gnd g610 nand2
X265 g712 g58 vdd gnd g743 and2
X245 g655 vdd gnd g723 not1
X138 g464 g465 vdd gnd g492 nor2
X27 g30 g31 vdd gnd g308 or2
X301 g51 g785 vdd gnd g791 and2
X114 g35 g417 vdd gnd g460 and2
X348 g841 g752 g654 vdd gnd g845 nand3
X331 g334 g819 vdd gnd g828 nor2
X122 g433 g1 vdd gnd g468 nand2
X102 g403 g404 vdd gnd g416 and2
X4 g1 g5 g9 vdd gnd g276 and3
X162 g485 g486 vdd gnd g518 nand2
X219 g585 g582 vdd gnd g658 and2
X296 g773 g774 vdd gnd g786 nor2
X364 g351 vdd gnd g861 not1
X355 g849 vdd gnd g852 not1
X320 g667 g805 vdd gnd g817 nor2
X230 g617 vdd gnd g690 not1
X213 g537 g573 vdd gnd g645 nor2
X356 g850 vdd gnd g853 not1
X87 g360 vdd gnd g401 not1
X200 g54 g550 vdd gnd g609 and2
X108 g407 g408 vdd gnd g434 and2
X184 g529 vdd gnd g570 not1
X359 g291 vdd gnd g856 not1
X156 g436 g44 vdd gnd g510 and2
X351 g844 vdd gnd g848 not1
X132 g448 g33 vdd gnd g486 or2
X135 g25 g451 vdd gnd g489 and2
X333 g821 vdd gnd g830 not1
X282 g741 g717 vdd gnd g765 nand2
X63 g293 vdd gnd g351 not1
X291 g702 g765 vdd gnd g776 and2
X167 g495 g496 vdd gnd g525 nor2
X180 g473 g525 vdd gnd g554 nand2
X141 g35 g468 vdd gnd g495 and2
X41 g45 g46 vdd gnd g329 or2
X278 g735 g747 g748 g719 vdd gnd g756 nand4
X103 g319 g389 g10 vdd gnd g417 and3
X239 g639 g58 vdd gnd g717 nand2
X295 g771 g772 vdd gnd g785 nor2
X13 g6 g7 g8 vdd gnd g292 and3
X145 g37 g468 vdd gnd g499 and2
X16 g11 g7 g17 vdd gnd g295 and3
X37 g41 g42 vdd gnd g325 or2
X382 g853 vdd gnd g879 not1
X252 g52 g677 vdd gnd g730 and2
X240 g629 g639 g58 vdd gnd g718 nand3
X312 g335 g791 vdd gnd g809 nor2
X107 g389 g319 g4 vdd gnd g433 nand3
X65 g295 vdd gnd g353 not1
X164 g316 g489 vdd gnd g522 nor2
X60 g280 g284 vdd gnd g348 nor2
X247 g53 g655 vdd gnd g725 and2
X72 g307 g308 vdd gnd g366 nand2
X127 g409 g434 vdd gnd g477 nor2
X49 g55 g56 vdd gnd g337 and2
X264 g712 g58 vdd gnd g742 nor2
X241 g620 g629 g639 g58 vdd gnd g719 nand4
X288 g693 g761 vdd gnd g773 nor2
X279 g733 g734 vdd gnd g760 nor2
X375 g823 vdd gnd g872 not1
X326 g812 vdd gnd g823 not1
X303 g51 g787 vdd gnd g793 and2
X39 g43 g44 vdd gnd g327 or2
X112 g405 g416 vdd gnd g448 nor2
X116 g36 g417 vdd gnd g462 and2
X313 g336 g792 vdd gnd g810 nor2
X304 g788 g770 g716 g514 vdd gnd g794 nand4
X225 g604 g601 vdd gnd g677 and2
X137 g26 g451 vdd gnd g491 and2
X327 g798 g578 vdd gnd g824 nand2
X172 g505 g506 vdd gnd g532 nand2
X93 g376 vdd gnd g407 not1
X344 g413 g833 vdd gnd g841 nor2
X29 g60 vdd gnd g310 not1
X146 g30 g451 vdd gnd g500 and2
X9 g11 g12 g15 vdd gnd g286 nand3
X25 g28 g29 vdd gnd g306 or2
X55 g273 vdd gnd g343 not1
X157 g436 g45 vdd gnd g511 and2
X323 g809 g760 g689 vdd gnd g820 nand3
X284 g742 g743 vdd gnd g769 nor2
X84 g350 vdd gnd g398 not1
X300 g677 g779 vdd gnd g790 and2
X19 g20 g21 vdd gnd g298 or2
X367 g356 vdd gnd g864 not1
X273 g585 g594 g672 vdd gnd g751 nand3
X372 g399 vdd gnd g869 not1
X74 g322 g323 vdd gnd g375 nor2
X349 g842 g753 g662 vdd gnd g846 nand3
X316 g650 g798 vdd gnd g813 nor2
X161 g483 g484 vdd gnd g515 nand2
X190 g538 g41 vdd gnd g578 or2
X51 g55 g57 vdd gnd g339 and2
X160 g436 g48 vdd gnd g514 nand2
X69 g301 g302 vdd gnd g357 nand2
X336 g51 g825 vdd gnd g833 and2
X208 g562 g47 vdd gnd g629 or2
X297 g775 g776 vdd gnd g787 nor2
X154 g436 g42 vdd gnd g508 and2
X332 g820 vdd gnd g829 not1
X210 g566 g48 vdd gnd g636 nand2
X7 g11 g8 g12 g13 vdd gnd g284 nand4
X381 g852 vdd gnd g878 not1
X256 g53 g682 vdd gnd g734 and2
X216 g578 g575 vdd gnd g650 and2
X177 g522 g490 vdd gnd g542 nand2
X204 g558 g46 vdd gnd g617 nand2
X176 g521 g488 vdd gnd g538 nand2
X98 g382 g385 vdd gnd g412 and2
X221 g591 vdd gnd g663 not1
X232 g337 g625 vdd gnd g697 nor2
X196 g546 g43 vdd gnd g594 or2
X26 g30 g31 vdd gnd g307 nand2
X287 g685 g756 vdd gnd g772 and2
X59 g279 vdd gnd g347 not1
X54 g269 vdd gnd g342 not1
X244 g53 g647 vdd gnd g722 and2
X262 g53 g698 vdd gnd g740 and2
X18 g18 g19 vdd gnd g297 and2
X298 g340 g777 vdd gnd g788 nor2
X126 g369 g427 vdd gnd g476 or2
X203 g54 g554 vdd gnd g616 and2
X220 g590 g508 vdd gnd g662 nor2
X379 g840 vdd gnd g876 not1
X362 g342 vdd gnd g859 not1
X68 g23 g298 vdd gnd g356 and2
X110 g414 vdd gnd g436 not1
X53 g55 g59 vdd gnd g341 and2
X92 g347 g352 vdd gnd g406 nand2
X346 g333 g835 vdd gnd g843 nor2
X131 g448 g33 vdd gnd g485 nand2
X337 g51 g826 vdd gnd g834 and2
X255 g52 g685 vdd gnd g733 and2
X17 g11 g7 g8 vdd gnd g296 and3
X134 g460 g461 vdd gnd g488 nor2
X352 g845 vdd gnd g849 not1
X342 g831 vdd gnd g839 not1
X187 g535 g536 vdd gnd g573 and2
X334 g822 vdd gnd g831 not1
X48 g50 g28 vdd gnd g336 and2
X212 g54 g566 vdd gnd g644 and2
X6 g1 g2 g3 g10 vdd gnd g280 nand4
X64 g294 vdd gnd g352 not1
X38 g43 g44 vdd gnd g326 nand2
X109 g410 g411 vdd gnd g435 and2
X192 g542 g42 vdd gnd g582 nand2
X32 g38 g34 vdd gnd g318 and2
X97 g385 vdd gnd g411 not1
X75 g324 g325 vdd gnd g376 nand2
X363 g344 vdd gnd g860 not1
X21 g24 g25 vdd gnd g302 or2
X8 g6 g12 vdd gnd g285 nand2
X80 g345 vdd gnd g389 not1
X3 g6 g7 g8 vdd gnd g273 and3
X292 g51 g769 vdd gnd g777 and2
X198 g550 g44 vdd gnd g601 nand2
X12 g6 g7 g17 vdd gnd g291 and3
X71 g305 g306 vdd gnd g363 nand2
X373 g645 vdd gnd g870 not1
X140 g466 g467 vdd gnd g494 nor2
X253 g53 g672 vdd gnd g731 and2
X360 g292 vdd gnd g857 not1
X148 g31 g451 vdd gnd g502 and2
X274 g721 g722 vdd gnd g752 nor2
X183 g476 g528 vdd gnd g566 nand2
X123 g369 g427 vdd gnd g473 or2
X222 g594 g591 vdd gnd g667 and2
X188 g570 g571 vdd gnd g574 and2
X330 g817 g818 vdd gnd g827 nor2
X24 g28 g29 vdd gnd g305 nand2
X151 g480 g49 vdd gnd g505 nand2
X378 g839 vdd gnd g875 not1
X227 g610 vdd gnd g682 not1
X339 g828 g755 g681 vdd gnd g836 nand3
X267 g53 g707 vdd gnd g745 and2
X85 g355 vdd gnd g399 not1
X370 g397 vdd gnd g867 not1
X281 g736 g737 vdd gnd g764 nor2
X211 g566 g48 vdd gnd g639 or2
X171 g503 g504 vdd gnd g529 nand2
X11 g6 g16 g8 vdd gnd g290 and3
X169 g499 g500 vdd gnd g527 nor2
X191 g54 g538 vdd gnd g581 and2
X350 g843 g754 g671 vdd gnd g847 nand3
X217 g581 g507 vdd gnd g654 nor2
X307 g585 g594 g604 g779 vdd gnd g797 nand4
X150 g32 g477 vdd gnd g504 or2
X317 g650 g798 vdd gnd g814 and2
X88 g357 g360 vdd gnd g402 and2
X250 g53 g663 vdd gnd g728 and2
X235 g339 g635 vdd gnd g706 nor2
X207 g562 g47 vdd gnd g626 nand2
X195 g546 g43 vdd gnd g591 nand2
X343 g832 vdd gnd g840 not1
X124 g369 g427 vdd gnd g474 or2
X357 g851 vdd gnd g854 not1
X178 g523 g492 vdd gnd g546 nand2
X99 g50 g369 vdd gnd g413 and2
X119 g310 g422 vdd gnd g465 and2
X45 g50 g25 vdd gnd g333 and2
X226 g609 g510 vdd gnd g681 nor2
X306 g594 g604 g779 vdd gnd g796 nand3
X238 g341 g644 vdd gnd g716 nor2
X263 g707 vdd gnd g741 not1
X231 g620 g617 vdd gnd g693 and2
X158 g436 g46 vdd gnd g512 nand2
X319 g658 g802 vdd gnd g816 and2
X175 g515 g518 vdd gnd g537 and2
X36 g41 g42 vdd gnd g324 nand2
X104 g389 g4 g287 vdd gnd g422 and3
X199 g550 g44 vdd gnd g604 or2
X361 g297 vdd gnd g858 not1
.subckt and3 a b c vdd vss z
m01 08 a vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m02 n1 a vss vss nmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m03 vdd b 08 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m04 sig6 b n1 vss nmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m05 08 c vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m06 08 c sig6 vss nmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m07 vdd 08 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m08 vss 08 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 08 vss 1.142f
c5 a vss 0.539f
c7 b vss 0.609f
c8 c vss 0.651f
c3 z vss 0.745f
.ends
.subckt nand3 a b c vdd vss z
m01 vdd a z vdd pmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m02 vss a sig2 vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m03 z b vdd vdd pmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m04 sig2 b sig3 vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m05 vdd c z vdd pmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m06 sig3 c z vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
c5 a vss 0.491f
c6 b vss 0.400f
c7 c vss 0.478f
c1 z vss 0.850f
.ends
.subckt nor2 a b vdd vss z
m01 vdd a 01 vdd pmos l=0.12u w=1.54u as=0.4081p ad=0.4081p ps=3.61u pd=3.61u
m02 vss a z vss nmos l=0.12u w=0.44u as=0.1166p ad=0.1166p ps=1.41u pd=1.41u
m03 01 b z vdd pmos l=0.12u w=1.54u as=0.4081p ad=0.4081p ps=3.61u pd=3.61u
m04 z b vss vss nmos l=0.12u w=0.44u as=0.1166p ad=0.1166p ps=1.41u pd=1.41u
c4 a vss 0.341f
c3 b vss 0.433f
c2 z vss 0.677f
.ends
.subckt nand4 a b c d vdd vss z
m01 vdd a z vdd pmos l=0.12u w=0.935u as=0.247775p ad=0.247775p ps=2.4u pd=2.4u
m02 vss a sig7 vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m03 z b vdd vdd pmos l=0.12u w=0.935u as=0.247775p ad=0.247775p ps=2.4u pd=2.4u
m04 sig7 b sig3 vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m05 vdd c z vdd pmos l=0.12u w=0.935u as=0.247775p ad=0.247775p ps=2.4u pd=2.4u
m06 sig3 c sig2 vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
m07 z d vdd vdd pmos l=0.12u w=0.935u as=0.247775p ad=0.247775p ps=2.4u pd=2.4u
m08 sig2 d z vss nmos l=0.12u w=1.1u as=0.2915p ad=0.2915p ps=2.73u pd=2.73u
c9 a vss 0.610f
c8 b vss 0.677f
c6 c vss 0.603f
c5 d vss 0.638f
c1 z vss 0.948f
.ends
.subckt or2 a b vdd vss z
m01 03 a vdd vdd pmos l=0.12u w=1.155u as=0.306075p ad=0.306075p ps=2.84u pd=2.84u
m02 sig1 a vss vss nmos l=0.12u w=0.33u as=0.08745p ad=0.08745p ps=1.19u pd=1.19u
m03 sig1 b 03 vdd pmos l=0.12u w=1.155u as=0.306075p ad=0.306075p ps=2.84u pd=2.84u
m04 vss b sig1 vss nmos l=0.12u w=0.33u as=0.08745p ad=0.08745p ps=1.19u pd=1.19u
m5 vdd sig1 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m6 vss sig1 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 a vss 0.464f
c5 b vss 0.507f
c1 sig1 vss 0.619f
c3 z vss 0.593f
.ends
.subckt nand2 a b vdd vss z
m01 vdd a z vdd pmos l=0.12u w=0.77u as=0.20405p ad=0.20405p ps=2.07u pd=2.07u
m02 vss a sig3 vss nmos l=0.12u w=0.66u as=0.1749p ad=0.1749p ps=1.85u pd=1.85u
m03 z b vdd vdd pmos l=0.12u w=0.77u as=0.20405p ad=0.20405p ps=2.07u pd=2.07u
m04 sig3 b z vss nmos l=0.12u w=0.66u as=0.1749p ad=0.1749p ps=1.85u pd=1.85u
c4 a vss 0.549f
c5 b vss 0.578f
c1 z vss 0.609f
.ends
.subckt and2 a b vdd vss z
m01 06 a vdd vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m02 n1 a vss vss nmos l=0.12u w=0.605u as=0.160325p ad=0.160325p ps=1.74u pd=1.74u
m03 vdd b 06 vdd pmos l=0.12u w=0.715u as=0.189475p ad=0.189475p ps=1.96u pd=1.96u
m04 06 b n1 vss nmos l=0.12u w=0.605u as=0.160325p ad=0.160325p ps=1.74u pd=1.74u
m05 vdd 06 z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m06 vss 06 z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c4 06 vss 0.724f
c5 a vss 0.663f
c6 b vss 0.538f
c3 z vss 0.595f
.ends
.subckt not1 a vdd vss z
m01 vdd a z vdd pmos l=0.12u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
m02 vss a z vss nmos l=0.12u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c3 a vss 0.384f
c2 z vss 0.576f
.ends
* simulation command:
.tran 1ps 1ns
.print tran V(g859) V(g861) V(g865) V(g870) V(g864) V(g866) V(g878) V(g862) V(g860) V(g869) V(g874) V(g863) V(g877) V(g876) V(g857) V(g871) V(g868) V(g856) V(g880) V(g873) V(g872) V(g875) V(g867) V(g858) V(g879) V(g855)
.end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
* PTM High Performance 45nm Metal Gate / High-K / Strained-Si
* nominal Vdd = 1.0V
.model nmos nmos level = 54
+version = 4.7.0 binunit = 1 paramchk= 1 mobmod = 0
+capmod = 2 igcmod = 1 igbmod = 1 geomod = 1
+diomod = 1 rdsmod = 0 rbodymod= 1 rgatemod= 1
+permod = 1 acnqsmod= 0 trnqsmod= 0
+tnom = 27 toxe = 1.25e-009 toxp = 1e-009 toxm = 1.25e-009
+dtox = 2.5e-010 epsrox = 3.9 wint = 5e-009 lint = 3.75e-009
+ll = 0 wl = 0 lln = 1 wln = 1
+lw = 0 ww = 0 lwn = 1 wwn = 1
+lwl = 0 wwl = 0 xpart = 0 toxref = 1.25e-009
+xl = -20e-9
+vth0 = 0.46893 k1 = 0.4 k2 = 0 k3 = 0
+k3b = 0 w0 = 2.5e-006 dvt0 = 1 dvt1 = 2
+dvt2 = 0 dvt0w = 0 dvt1w = 0 dvt2w = 0
+dsub = 0.1 minv = 0.05 voffl = 0 dvtp0 = 1e-010
+dvtp1 = 0.1 lpe0 = 0 lpeb = 0 xj = 1.4e-008
+ngate = 1e+023 ndep = 3.24e+018 nsd = 2e+020 phin = 0
+cdsc = 0 cdscb = 0 cdscd = 0 cit = 0
+voff = -0.13 nfactor = 2.22 eta0 = 0.0055 etab = 0
+vfb = -0.55 u0 = 0.054 ua = 6e-010 ub = 1.2e-018
+uc = 0 vsat = 170000 a0 = 1 ags = 0
+a1 = 0 a2 = 1 b0 = 0 b1 = 0
+keta = 0.04 dwg = 0 dwb = 0 pclm = 0.02
+pdiblc1 = 0.001 pdiblc2 = 0.001 pdiblcb = -0.005 drout = 0.5
+pvag = 1e-020 delta = 0.01 pscbe1 = 8.14e+008 pscbe2 = 1e-007
+fprout = 0.2 pdits = 0.08 pditsd = 0.23 pditsl = 2300000
+rsh = 5 rdsw = 155 rsw = 80 rdw = 80
+rdswmin = 0 rdwmin = 0 rswmin = 0 prwg = 0
+prwb = 0 wr = 1 alpha0 = 0.074 alpha1 = 0.005
+beta0 = 30 agidl = 0.0002 bgidl = 2.1e+009 cgidl = 0.0002
+egidl = 0.8 aigbacc = 0.012 bigbacc = 0.0028 cigbacc = 0.002
+nigbacc = 1 aigbinv = 0.014 bigbinv = 0.004 cigbinv = 0.004
+eigbinv = 1.1 nigbinv = 3 aigc = 0.02 bigc = 0.0025
+cigc = 0.002 aigsd = 0.02 bigsd = 0.0025 cigsd = 0.002
+nigc = 1 poxedge = 1 pigcd = 1 ntox = 1
+xrcrg1 = 12 xrcrg2 = 5
+cgso = 1.1e-010 cgdo = 1.1e-010 cgbo = 2.56e-011 cgdl = 2.653e-010
+cgsl = 2.653e-010 ckappas = 0.03 ckappad = 0.03 acde = 1
+moin = 15 noff = 0.9 voffcv = 0.02
+kt1 = -0.11 kt1l = 0 kt2 = 0.022 ute = -1.5
+ua1 = 4.31e-009 ub1 = 7.61e-018 uc1 = -5.6e-011 prt = 0
+at = 33000
+fnoimod = 1 tnoimod = 0
+jss = 0.0001 jsws = 1e-011 jswgs = 1e-010 njs = 1
+ijthsfwd= 0.01 ijthsrev= 0.001 bvs = 10 xjbvs = 1
+jsd = 0.0001 jswd = 1e-011 jswgd = 1e-010 njd = 1
+ijthdfwd= 0.01 ijthdrev= 0.001 bvd = 10 xjbvd = 1
+pbs = 1 cjs = 0.0005 mjs = 0.5 pbsws = 1
+cjsws = 5e-010 mjsws = 0.33 pbswgs = 1 cjswgs = 3e-010
+mjswgs = 0.33 pbd = 1 cjd = 0.0005 mjd = 0.5
+pbswd = 1 cjswd = 5e-010 mjswd = 0.33 pbswgd = 1
+cjswgd = 5e-010 mjswgd = 0.33 tpb = 0.005 tcj = 0.001
+tpbsw = 0.005 tcjsw = 0.001 tpbswg = 0.005 tcjswg = 0.001
+xtis = 3 xtid = 3
+dmcg = 0 dmci = 0 dmdg = 0 dmcgt = 0
+dwj = 0 xgw = 0 xgl = 0
+rshg = 0.4 gbmin = 1e-010 rbpb = 5 rbpd = 15
+rbps = 15 rbdb = 15 rbsb = 15 ngcon = 1
.model pmos pmos level = 54
+version = 4.7.0 binunit = 1 paramchk= 1 mobmod = 0
+capmod = 2 igcmod = 1 igbmod = 1 geomod = 1
+diomod = 1 rdsmod = 0 rbodymod= 1 rgatemod= 1
+permod = 1 acnqsmod= 0 trnqsmod= 0
+tnom = 27 toxe = 1.3e-009 toxp = 1e-009 toxm = 1.3e-009
+dtox = 3e-010 epsrox = 3.9 wint = 5e-009 lint = 3.75e-009
+ll = 0 wl = 0 lln = 1 wln = 1
+lw = 0 ww = 0 lwn = 1 wwn = 1
+lwl = 0 wwl = 0 xpart = 0 toxref = 1.3e-009
+xl = -20e-9
+vth0 = -0.49158 k1 = 0.4 k2 = -0.01 k3 = 0
+k3b = 0 w0 = 2.5e-006 dvt0 = 1 dvt1 = 2
+dvt2 = -0.032 dvt0w = 0 dvt1w = 0 dvt2w = 0
+dsub = 0.1 minv = 0.05 voffl = 0 dvtp0 = 1e-011
+dvtp1 = 0.05 lpe0 = 0 lpeb = 0 xj = 1.4e-008
+ngate = 1e+023 ndep = 2.44e+018 nsd = 2e+020 phin = 0
+cdsc = 0 cdscb = 0 cdscd = 0 cit = 0
+voff = -0.126 nfactor = 2.1 eta0 = 0.0055 etab = 0
+vfb = 0.55 u0 = 0.02 ua = 2e-009 ub = 5e-019
+uc = 0 vsat = 150000 a0 = 1 ags = 1e-020
+a1 = 0 a2 = 1 b0 = 0 b1 = 0
+keta = -0.047 dwg = 0 dwb = 0 pclm = 0.12
+pdiblc1 = 0.001 pdiblc2 = 0.001 pdiblcb = 3.4e-008 drout = 0.56
+pvag = 1e-020 delta = 0.01 pscbe1 = 8.14e+008 pscbe2 = 9.58e-007
+fprout = 0.2 pdits = 0.08 pditsd = 0.23 pditsl = 2300000
+rsh = 5 rdsw = 155 rsw = 75 rdw = 75
+rdswmin = 0 rdwmin = 0 rswmin = 0 prwg = 0
+prwb = 0 wr = 1 alpha0 = 0.074 alpha1 = 0.005
+beta0 = 30 agidl = 0.0002 bgidl = 2.1e+009 cgidl = 0.0002
+egidl = 0.8 aigbacc = 0.012 bigbacc = 0.0028 cigbacc = 0.002
+nigbacc = 1 aigbinv = 0.014 bigbinv = 0.004 cigbinv = 0.004
+eigbinv = 1.1 nigbinv = 3 aigc = 0.010687 bigc = 0.0012607
+cigc = 0.0008 aigsd = 0.010687 bigsd = 0.0012607 cigsd = 0.0008
+nigc = 1 poxedge = 1 pigcd = 1 ntox = 1
+xrcrg1 = 12 xrcrg2 = 5
+cgso = 1.1e-010 cgdo = 1.1e-010 cgbo = 2.56e-011 cgdl = 2.653e-010
+cgsl = 2.653e-010 ckappas = 0.03 ckappad = 0.03 acde = 1
+moin = 15 noff = 0.9 voffcv = 0.02
+kt1 = -0.11 kt1l = 0 kt2 = 0.022 ute = -1.5
+ua1 = 4.31e-009 ub1 = 7.61e-018 uc1 = -5.6e-011 prt = 0
+at = 33000
+fnoimod = 1 tnoimod = 0
+jss = 0.0001 jsws = 1e-011 jswgs = 1e-010 njs = 1
+ijthsfwd= 0.01 ijthsrev= 0.001 bvs = 10 xjbvs = 1
+jsd = 0.0001 jswd = 1e-011 jswgd = 1e-010 njd = 1
+ijthdfwd= 0.01 ijthdrev= 0.001 bvd = 10 xjbvd = 1
+pbs = 1 cjs = 0.0005 mjs = 0.5 pbsws = 1
+cjsws = 5e-010 mjsws = 0.33 pbswgs = 1 cjswgs = 3e-010
+mjswgs = 0.33 pbd = 1 cjd = 0.0005 mjd = 0.5
+pbswd = 1 cjswd = 5e-010 mjswd = 0.33 pbswgd = 1
+cjswgd = 5e-010 mjswgd = 0.33 tpb = 0.005 tcj = 0.001
+tpbsw = 0.005 tcjsw = 0.001 tpbswg = 0.005 tcjswg = 0.001
+xtis = 3 xtid = 3
+dmcg = 0 dmci = 0 dmdg = 0 dmcgt = 0
+dwj = 0 xgw = 0 xgl = 0
+rshg = 0.4 gbmin = 1e-010 rbpb = 5 rbpd = 15
+rbps = 15 rbdb = 15 rbsb = 15 ngcon = 1

View File

@ -176,7 +176,13 @@ ngspice_LDADD += \
maths/misc/libmathmisc.la \
maths/fft/libmathfft.la \
maths/poly/libpoly.la \
maths/ni/libni.la \
maths/ni/libni.la
if KLU_WANTED
ngspice_LDADD += maths/KLU/libKLU.la
endif
ngspice_LDADD += \
maths/sparse/libsparse.la \
misc/libmisc.la
@ -279,6 +285,10 @@ ngmultidec_LDADD = \
maths/sparse/libsparse.la \
misc/libmisc.la
if KLU_WANTED
ngmultidec_LDADD += maths/KLU/libKLU.la
endif
## ngmakeidx:
@ -411,6 +421,10 @@ libspice_la_LIBADD += \
ciderlib/support/libcidersuprt.la
endif
if KLU_WANTED
libspice_la_LIBADD += maths/KLU/libKLU.la
endif
libspice_la_LIBADD += \
maths/deriv/libderiv.la \
maths/cmaths/libcmaths.la \

View File

@ -176,6 +176,14 @@ com_version(wordlist *wl)
fprintf(cp_out,
"******\n"
"** %s-%s : %s\n"
#ifdef KLU
"** Compiled with KLU Direct Linear Solver\n"
"** (ASRC, CPL, NDEV and URC models not supported yet)\n"
#else
"** Compiled with Sparse Direct Linear Solver\n"
#endif
"** The U. C. Berkeley CAD Group\n"
"** Copyright 1985-1994, Regents of the University of California.\n"
"** %s\n",
@ -208,6 +216,14 @@ com_version(wordlist *wl)
fprintf(cp_out,
"******\n"
"** %s-%s : %s\n"
#ifdef KLU
"** Compiled with KLU Direct Linear Solver\n"
"** (ASRC, CPL, NDEV and URC models not supported yet)\n"
#else
"** Compiled with Sparse Direct Linear Solver\n"
#endif
"** The U. C. Berkeley CAD Group\n"
"** Copyright 1985-1994, Regents of the University of California.\n"
"** %s\n",

View File

@ -0,0 +1,151 @@
/* ========================================================================== */
/* === UFconfig.h =========================================================== */
/* ========================================================================== */
/* Configuration file for SuiteSparse: a Suite of Sparse matrix packages
* (AMD, COLAMD, CCOLAMD, CAMD, CHOLMOD, UMFPACK, CXSparse, and others).
*
* UFconfig.h provides the definition of the long integer. On most systems,
* a C program can be compiled in LP64 mode, in which long's and pointers are
* both 64-bits, and int's are 32-bits. Windows 64, however, uses the LLP64
* model, in which int's and long's are 32-bits, and long long's and pointers
* are 64-bits.
*
* SuiteSparse packages that include long integer versions are
* intended for the LP64 mode. However, as a workaround for Windows 64
* (and perhaps other systems), the long integer can be redefined.
*
* If _WIN64 is defined, then the __int64 type is used instead of long.
*
* The long integer can also be defined at compile time. For example, this
* could be added to UFconfig.mk:
*
* CFLAGS = -O -D'UF_long=long long' -D'UF_long_max=9223372036854775801' \
* -D'UF_long_idd="lld"'
*
* This file defines UF_long as either long (on all but _WIN64) or
* __int64 on Windows 64. The intent is that a UF_long is always a 64-bit
* integer in a 64-bit code. ptrdiff_t might be a better choice than long;
* it is always the same size as a pointer.
*
* This file also defines the SUITESPARSE_VERSION and related definitions.
*
* Copyright (c) 2007, University of Florida. No licensing restrictions
* apply to this file or to the UFconfig directory. Author: Timothy A. Davis.
*/
#ifndef _UFCONFIG_H
#define _UFCONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <limits.h>
#include <stdlib.h>
/* ========================================================================== */
/* === UF_long ============================================================== */
/* ========================================================================== */
#ifndef UF_long
#ifdef _WIN64
#define UF_long __int64
#define UF_long_max _I64_MAX
#define UF_long_idd "I64d"
#else
#define UF_long long
#define UF_long_max LONG_MAX
#define UF_long_idd "ld"
#endif
#define UF_long_id "%" UF_long_idd
#endif
/* ========================================================================== */
/* === UFconfig parameters and functions ==================================== */
/* ========================================================================== */
/* SuiteSparse-wide parameters will be placed in this struct. So far, they
are only used by RBio. */
typedef struct UFconfig_struct
{
void *(*malloc_memory) (size_t) ; /* pointer to malloc */
void *(*realloc_memory) (void *, size_t) ; /* pointer to realloc */
void (*free_memory) (void *) ; /* pointer to free */
void *(*calloc_memory) (size_t, size_t) ; /* pointer to calloc */
} UFconfig ;
void *UFmalloc /* pointer to allocated block of memory */
(
size_t nitems, /* number of items to malloc (>=1 is enforced) */
size_t size_of_item, /* sizeof each item */
int *ok, /* TRUE if successful, FALSE otherwise */
UFconfig *config /* SuiteSparse-wide configuration */
) ;
void *UFfree /* always returns NULL */
(
void *p, /* block to free */
UFconfig *config /* SuiteSparse-wide configuration */
) ;
/* ========================================================================== */
/* === SuiteSparse version ================================================== */
/* ========================================================================== */
/* SuiteSparse is not a package itself, but a collection of packages, some of
* which must be used together (UMFPACK requires AMD, CHOLMOD requires AMD,
* COLAMD, CAMD, and CCOLAMD, etc). A version number is provided here for the
* collection itself. The versions of packages within each version of
* SuiteSparse are meant to work together. Combining one packge from one
* version of SuiteSparse, with another package from another version of
* SuiteSparse, may or may not work.
*
* SuiteSparse Version 3.7.0 contains the following packages:
*
* UFconfig version 3.7.0 (version always the same as SuiteSparse)
* AMD version 2.2.3
* CAMD version 2.2.3
* CCOLAMD version 2.7.4
* COLAMD version 2.7.4
* BTF version 1.1.3
* CHOLMOD version 1.7.4
* CSparse3 version 3.0.2
* CSparse version 2.2.6
* CXSparse version 2.2.6
* KLU version 1.1.3
* LDL version 2.0.4
* RBio version 2.0.2
* SPQR version 1.2.3 (also called SuiteSparseQR)
* UFcollection version 1.6.0
* UMFPACK version 5.5.2
* SSMULT version 2.0.3
* spqr_rank version 1.0.0
* MATLAB_Tools various packages & M-files. No specific version number.
*
* Other package dependencies:
* BLAS required by CHOLMOD and UMFPACK
* LAPACK required by CHOLMOD
* METIS 4.0.1 required by CHOLMOD (optional) and KLU (optional)
*/
#define SUITESPARSE_DATE "Dec 15, 2011"
#define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub))
#define SUITESPARSE_MAIN_VERSION 3
#define SUITESPARSE_SUB_VERSION 7
#define SUITESPARSE_SUBSUB_VERSION 0
#define SUITESPARSE_VERSION \
SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION)
#ifdef __cplusplus
}
#endif
#endif

412
src/include/ngspice/amd.h Normal file
View File

@ -0,0 +1,412 @@
/* ========================================================================= */
/* === AMD: approximate minimum degree ordering =========================== */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD Version 2.2, Copyright (c) 2007 by Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* AMD finds a symmetric ordering P of a matrix A so that the Cholesky
* factorization of P*A*P' has fewer nonzeros and takes less work than the
* Cholesky factorization of A. If A is not symmetric, then it performs its
* ordering on the matrix A+A'. Two sets of user-callable routines are
* provided, one for int integers and the other for UF_long integers.
*
* The method is based on the approximate minimum degree algorithm, discussed
* in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm",
* SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp.
* 886-905, 1996. This package can perform both the AMD ordering (with
* aggressive absorption), and the AMDBAR ordering (without aggressive
* absorption) discussed in the above paper. This package differs from the
* Fortran codes discussed in the paper:
*
* (1) it can ignore "dense" rows and columns, leading to faster run times
* (2) it computes the ordering of A+A' if A is not symmetric
* (3) it is followed by a depth-first post-ordering of the assembly tree
* (or supernodal elimination tree)
*
* For historical reasons, the Fortran versions, amd.f and amdbar.f, have
* been left (nearly) unchanged. They compute the identical ordering as
* described in the above paper.
*/
#ifndef AMD_H
#define AMD_H
/* make it easy for C++ programs to include AMD */
#ifdef __cplusplus
extern "C" {
#endif
/* get the definition of size_t: */
#include <stddef.h>
/* define UF_long */
#include "UFconfig.h"
int amd_order /* returns AMD_OK, AMD_OK_BUT_JUMBLED,
* AMD_INVALID, or AMD_OUT_OF_MEMORY */
(
int n, /* A is n-by-n. n must be >= 0. */
const int Ap [ ], /* column pointers for A, of size n+1 */
const int Ai [ ], /* row indices of A, of size nz = Ap [n] */
int P [ ], /* output permutation, of size n */
double Control [ ], /* input Control settings, of size AMD_CONTROL */
double Info [ ] /* output Info statistics, of size AMD_INFO */
) ;
UF_long amd_l_order /* see above for description of arguments */
(
UF_long n,
const UF_long Ap [ ],
const UF_long Ai [ ],
UF_long P [ ],
double Control [ ],
double Info [ ]
) ;
/* Input arguments (not modified):
*
* n: the matrix A is n-by-n.
* Ap: an int/UF_long array of size n+1, containing column pointers of A.
* Ai: an int/UF_long array of size nz, containing the row indices of A,
* where nz = Ap [n].
* Control: a double array of size AMD_CONTROL, containing control
* parameters. Defaults are used if Control is NULL.
*
* Output arguments (not defined on input):
*
* P: an int/UF_long array of size n, containing the output permutation. If
* row i is the kth pivot row, then P [k] = i. In MATLAB notation,
* the reordered matrix is A (P,P).
* Info: a double array of size AMD_INFO, containing statistical
* information. Ignored if Info is NULL.
*
* On input, the matrix A is stored in column-oriented form. The row indices
* of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1].
*
* If the row indices appear in ascending order in each column, and there
* are no duplicate entries, then amd_order is slightly more efficient in
* terms of time and memory usage. If this condition does not hold, a copy
* of the matrix is created (where these conditions do hold), and the copy is
* ordered. This feature is new to v2.0 (v1.2 and earlier required this
* condition to hold for the input matrix).
*
* Row indices must be in the range 0 to
* n-1. Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros
* in A. The array Ap is of size n+1, and the array Ai is of size nz = Ap [n].
* The matrix does not need to be symmetric, and the diagonal does not need to
* be present (if diagonal entries are present, they are ignored except for
* the output statistic Info [AMD_NZDIAG]). The arrays Ai and Ap are not
* modified. This form of the Ap and Ai arrays to represent the nonzero
* pattern of the matrix A is the same as that used internally by MATLAB.
* If you wish to use a more flexible input structure, please see the
* umfpack_*_triplet_to_col routines in the UMFPACK package, at
* http://www.cise.ufl.edu/research/sparse/umfpack.
*
* Restrictions: n >= 0. Ap [0] = 0. Ap [j] <= Ap [j+1] for all j in the
* range 0 to n-1. nz = Ap [n] >= 0. Ai [0..nz-1] must be in the range 0
* to n-1. Finally, Ai, Ap, and P must not be NULL. If any of these
* restrictions are not met, AMD returns AMD_INVALID.
*
* AMD returns:
*
* AMD_OK if the matrix is valid and sufficient memory can be allocated to
* perform the ordering.
*
* AMD_OUT_OF_MEMORY if not enough memory can be allocated.
*
* AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is
* NULL.
*
* AMD_OK_BUT_JUMBLED if the matrix had unsorted columns, and/or duplicate
* entries, but was otherwise valid.
*
* The AMD routine first forms the pattern of the matrix A+A', and then
* computes a fill-reducing ordering, P. If P [k] = i, then row/column i of
* the original is the kth pivotal row. In MATLAB notation, the permuted
* matrix is A (P,P), except that 0-based indexing is used instead of the
* 1-based indexing in MATLAB.
*
* The Control array is used to set various parameters for AMD. If a NULL
* pointer is passed, default values are used. The Control array is not
* modified.
*
* Control [AMD_DENSE]: controls the threshold for "dense" rows/columns.
* A dense row/column in A+A' can cause AMD to spend a lot of time in
* ordering the matrix. If Control [AMD_DENSE] >= 0, rows/columns
* with more than Control [AMD_DENSE] * sqrt (n) entries are ignored
* during the ordering, and placed last in the output order. The
* default value of Control [AMD_DENSE] is 10. If negative, no
* rows/columns are treated as "dense". Rows/columns with 16 or
* fewer off-diagonal entries are never considered "dense".
*
* Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive
* absorption, in which a prior element is absorbed into the current
* element if is a subset of the current element, even if it is not
* adjacent to the current pivot element (refer to Amestoy, Davis,
* & Duff, 1996, for more details). The default value is nonzero,
* which means to perform aggressive absorption. This nearly always
* leads to a better ordering (because the approximate degrees are
* more accurate) and a lower execution time. There are cases where
* it can lead to a slightly worse ordering, however. To turn it off,
* set Control [AMD_AGGRESSIVE] to 0.
*
* Control [2..4] are not used in the current version, but may be used in
* future versions.
*
* The Info array provides statistics about the ordering on output. If it is
* not present, the statistics are not returned. This is not an error
* condition.
*
* Info [AMD_STATUS]: the return value of AMD, either AMD_OK,
* AMD_OK_BUT_JUMBLED, AMD_OUT_OF_MEMORY, or AMD_INVALID.
*
* Info [AMD_N]: n, the size of the input matrix
*
* Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n]
*
* Info [AMD_SYMMETRY]: the symmetry of the matrix A. It is the number
* of "matched" off-diagonal entries divided by the total number of
* off-diagonal entries. An entry A(i,j) is matched if A(j,i) is also
* an entry, for any pair (i,j) for which i != j. In MATLAB notation,
* S = spones (A) ;
* B = tril (S, -1) + triu (S, 1) ;
* symmetry = nnz (B & B') / nnz (B) ;
*
* Info [AMD_NZDIAG]: the number of entries on the diagonal of A.
*
* Info [AMD_NZ_A_PLUS_AT]: the number of nonzeros in A+A', excluding the
* diagonal. If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1)
* with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n
* (the smallest possible value). If A is perfectly unsymmetric
* (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for
* example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz
* (the largest possible value).
*
* Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were
* removed from A prior to ordering. These are placed last in the
* output order P.
*
* Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes. In the
* current version, this is 1.2 * Info [AMD_NZ_A_PLUS_AT] + 9*n
* times the size of an integer. This is at most 2.4nz + 9n. This
* excludes the size of the input arguments Ai, Ap, and P, which have
* a total size of nz + 2*n + 1 integers.
*
* Info [AMD_NCMPA]: the number of garbage collections performed.
*
* Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal).
* This is a slight upper bound because mass elimination is combined
* with the approximate degree update. It is a rough upper bound if
* there are many "dense" rows/columns. The rest of the statistics,
* below, are also slight or rough upper bounds, for the same reasons.
* The post-ordering of the assembly tree might also not exactly
* correspond to a true elimination tree postordering.
*
* Info [AMD_NDIV]: the number of divide operations for a subsequent LDL'
* or LU factorization of the permuted matrix A (P,P).
*
* Info [AMD_NMULTSUBS_LDL]: the number of multiply-subtract pairs for a
* subsequent LDL' factorization of A (P,P).
*
* Info [AMD_NMULTSUBS_LU]: the number of multiply-subtract pairs for a
* subsequent LU factorization of A (P,P), assuming that no numerical
* pivoting is required.
*
* Info [AMD_DMAX]: the maximum number of nonzeros in any column of L,
* including the diagonal.
*
* Info [14..19] are not used in the current version, but may be used in
* future versions.
*/
/* ------------------------------------------------------------------------- */
/* direct interface to AMD */
/* ------------------------------------------------------------------------- */
/* amd_2 is the primary AMD ordering routine. It is not meant to be
* user-callable because of its restrictive inputs and because it destroys
* the user's input matrix. It does not check its inputs for errors, either.
* However, if you can work with these restrictions it can be faster than
* amd_order and use less memory (assuming that you can create your own copy
* of the matrix for AMD to destroy). Refer to AMD/Source/amd_2.c for a
* description of each parameter. */
void amd_2
(
int n,
int Pe [ ],
int Iw [ ],
int Len [ ],
int iwlen,
int pfree,
int Nv [ ],
int Next [ ],
int Last [ ],
int Head [ ],
int Elen [ ],
int Degree [ ],
int W [ ],
double Control [ ],
double Info [ ]
) ;
void amd_l2
(
UF_long n,
UF_long Pe [ ],
UF_long Iw [ ],
UF_long Len [ ],
UF_long iwlen,
UF_long pfree,
UF_long Nv [ ],
UF_long Next [ ],
UF_long Last [ ],
UF_long Head [ ],
UF_long Elen [ ],
UF_long Degree [ ],
UF_long W [ ],
double Control [ ],
double Info [ ]
) ;
/* ------------------------------------------------------------------------- */
/* amd_valid */
/* ------------------------------------------------------------------------- */
/* Returns AMD_OK or AMD_OK_BUT_JUMBLED if the matrix is valid as input to
* amd_order; the latter is returned if the matrix has unsorted and/or
* duplicate row indices in one or more columns. Returns AMD_INVALID if the
* matrix cannot be passed to amd_order. For amd_order, the matrix must also
* be square. The first two arguments are the number of rows and the number
* of columns of the matrix. For its use in AMD, these must both equal n.
*
* NOTE: this routine returned TRUE/FALSE in v1.2 and earlier.
*/
int amd_valid
(
int n_row, /* # of rows */
int n_col, /* # of columns */
const int Ap [ ], /* column pointers, of size n_col+1 */
const int Ai [ ] /* row indices, of size Ap [n_col] */
) ;
UF_long amd_l_valid
(
UF_long n_row,
UF_long n_col,
const UF_long Ap [ ],
const UF_long Ai [ ]
) ;
/* ------------------------------------------------------------------------- */
/* AMD memory manager and printf routines */
/* ------------------------------------------------------------------------- */
/* The user can redefine these to change the malloc, free, and printf routines
* that AMD uses. */
#ifndef EXTERN
#define EXTERN extern
#endif
EXTERN void *(*amd_malloc) (size_t) ; /* pointer to malloc */
EXTERN void (*amd_free) (void *) ; /* pointer to free */
EXTERN void *(*amd_realloc) (void *, size_t) ; /* pointer to realloc */
EXTERN void *(*amd_calloc) (size_t, size_t) ; /* pointer to calloc */
EXTERN int (*amd_printf) (const char *, ...) ; /* pointer to printf */
/* ------------------------------------------------------------------------- */
/* AMD Control and Info arrays */
/* ------------------------------------------------------------------------- */
/* amd_defaults: sets the default control settings */
void amd_defaults (double Control [ ]) ;
void amd_l_defaults (double Control [ ]) ;
/* amd_control: prints the control settings */
void amd_control (double Control [ ]) ;
void amd_l_control (double Control [ ]) ;
/* amd_info: prints the statistics */
void amd_info (double Info [ ]) ;
void amd_l_info (double Info [ ]) ;
#define AMD_CONTROL 5 /* size of Control array */
#define AMD_INFO 20 /* size of Info array */
/* contents of Control */
#define AMD_DENSE 0 /* "dense" if degree > Control [0] * sqrt (n) */
#define AMD_AGGRESSIVE 1 /* do aggressive absorption if Control [1] != 0 */
/* default Control settings */
#define AMD_DEFAULT_DENSE 10.0 /* default "dense" degree 10*sqrt(n) */
#define AMD_DEFAULT_AGGRESSIVE 1 /* do aggressive absorption by default */
/* contents of Info */
#define AMD_STATUS 0 /* return value of amd_order and amd_l_order */
#define AMD_N 1 /* A is n-by-n */
#define AMD_NZ 2 /* number of nonzeros in A */
#define AMD_SYMMETRY 3 /* symmetry of pattern (1 is sym., 0 is unsym.) */
#define AMD_NZDIAG 4 /* # of entries on diagonal */
#define AMD_NZ_A_PLUS_AT 5 /* nz in A+A' */
#define AMD_NDENSE 6 /* number of "dense" rows/columns in A */
#define AMD_MEMORY 7 /* amount of memory used by AMD */
#define AMD_NCMPA 8 /* number of garbage collections in AMD */
#define AMD_LNZ 9 /* approx. nz in L, excluding the diagonal */
#define AMD_NDIV 10 /* number of fl. point divides for LU and LDL' */
#define AMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */
#define AMD_NMULTSUBS_LU 12 /* number of fl. point (*,-) pairs for LU */
#define AMD_DMAX 13 /* max nz. in any column of L, incl. diagonal */
/* ------------------------------------------------------------------------- */
/* return values of AMD */
/* ------------------------------------------------------------------------- */
#define AMD_OK 0 /* success */
#define AMD_OUT_OF_MEMORY -1 /* malloc failed, or problem too large */
#define AMD_INVALID -2 /* input arguments are not valid */
#define AMD_OK_BUT_JUMBLED 1 /* input matrix is OK for amd_order, but
* columns were not sorted, and/or duplicate entries were present. AMD had
* to do extra work before ordering the matrix. This is a warning, not an
* error. */
/* ========================================================================== */
/* === AMD version ========================================================== */
/* ========================================================================== */
/* AMD Version 1.2 and later include the following definitions.
* As an example, to test if the version you are using is 1.2 or later:
*
* #ifdef AMD_VERSION
* if (AMD_VERSION >= AMD_VERSION_CODE (1,2)) ...
* #endif
*
* This also works during compile-time:
*
* #if defined(AMD_VERSION) && (AMD_VERSION >= AMD_VERSION_CODE (1,2))
* printf ("This is version 1.2 or later\n") ;
* #else
* printf ("This is an early version\n") ;
* #endif
*
* Versions 1.1 and earlier of AMD do not include a #define'd version number.
*/
#define AMD_DATE "Dec 7, 2011"
#define AMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
#define AMD_MAIN_VERSION 2
#define AMD_SUB_VERSION 2
#define AMD_SUBSUB_VERSION 3
#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION,AMD_SUB_VERSION)
#ifdef __cplusplus
}
#endif
#endif

263
src/include/ngspice/btf.h Normal file
View File

@ -0,0 +1,263 @@
/* ========================================================================== */
/* === BTF package ========================================================== */
/* ========================================================================== */
/* BTF_MAXTRANS: find a column permutation Q to give A*Q a zero-free diagonal
* BTF_STRONGCOMP: find a symmetric permutation P to put P*A*P' into block
* upper triangular form.
* BTF_ORDER: do both of the above (btf_maxtrans then btf_strongcomp).
*
* Copyright (c) 2004-2007. Tim Davis, University of Florida,
* with support from Sandia National Laboratories. All Rights Reserved.
*/
/* ========================================================================== */
/* === BTF_MAXTRANS ========================================================= */
/* ========================================================================== */
/* BTF_MAXTRANS: finds a permutation of the columns of a matrix so that it has a
* zero-free diagonal. The input is an m-by-n sparse matrix in compressed
* column form. The array Ap of size n+1 gives the starting and ending
* positions of the columns in the array Ai. Ap[0] must be zero. The array Ai
* contains the row indices of the nonzeros of the matrix A, and is of size
* Ap[n]. The row indices of column j are located in Ai[Ap[j] ... Ap[j+1]-1].
* Row indices must be in the range 0 to m-1. Duplicate entries may be present
* in any given column. The input matrix is not checked for validity (row
* indices out of the range 0 to m-1 will lead to an undeterminate result -
* possibly a core dump, for example). Row indices in any given column need
* not be in sorted order. However, if they are sorted and the matrix already
* has a zero-free diagonal, then the identity permutation is returned.
*
* The output of btf_maxtrans is an array Match of size n. If row i is matched
* with column j, then A(i,j) is nonzero, and then Match[i] = j. If the matrix
* is structurally nonsingular, all entries in the Match array are unique, and
* Match can be viewed as a column permutation if A is square. That is, column
* k of the original matrix becomes column Match[k] of the permuted matrix. In
* MATLAB, this can be expressed as (for non-structurally singular matrices):
*
* Match = maxtrans (A) ;
* B = A (:, Match) ;
*
* except of course here the A matrix and Match vector are all 0-based (rows
* and columns in the range 0 to n-1), not 1-based (rows/cols in range 1 to n).
* The MATLAB dmperm routine returns a row permutation. See the maxtrans
* mexFunction for more details.
*
* If row i is not matched to any column, then Match[i] is == -1. The
* btf_maxtrans routine returns the number of nonzeros on diagonal of the
* permuted matrix.
*
* In the MATLAB mexFunction interface to btf_maxtrans, 1 is added to the Match
* array to obtain a 1-based permutation. Thus, in MATLAB where A is m-by-n:
*
* q = maxtrans (A) ; % has entries in the range 0:n
* q % a column permutation (only if sprank(A)==n)
* B = A (:, q) ; % permuted matrix (only if sprank(A)==n)
* sum (q > 0) ; % same as "sprank (A)"
*
* This behaviour differs from p = dmperm (A) in MATLAB, which returns the
* matching as p(j)=i if row i and column j are matched, and p(j)=0 if column j
* is unmatched.
*
* p = dmperm (A) ; % has entries in the range 0:m
* p % a row permutation (only if sprank(A)==m)
* B = A (p, :) ; % permuted matrix (only if sprank(A)==m)
* sum (p > 0) ; % definition of sprank (A)
*
* This algorithm is based on the paper "On Algorithms for obtaining a maximum
* transversal" by Iain Duff, ACM Trans. Mathematical Software, vol 7, no. 1,
* pp. 315-330, and "Algorithm 575: Permutations for a zero-free diagonal",
* same issue, pp. 387-390. Algorithm 575 is MC21A in the Harwell Subroutine
* Library. This code is not merely a translation of the Fortran code into C.
* It is a completely new implementation of the basic underlying method (depth
* first search over a subgraph with nodes corresponding to columns matched so
* far, and cheap matching). This code was written with minimal observation of
* the MC21A/B code itself. See comments below for a comparison between the
* maxtrans and MC21A/B codes.
*
* This routine operates on a column-form matrix and produces a column
* permutation. MC21A uses a row-form matrix and produces a row permutation.
* The difference is merely one of convention in the comments and interpretation
* of the inputs and outputs. If you want a row permutation, simply pass a
* compressed-row sparse matrix to this routine and you will get a row
* permutation (just like MC21A). Similarly, you can pass a column-oriented
* matrix to MC21A and it will happily return a column permutation.
*/
#ifndef _BTF_H
#define _BTF_H
/* make it easy for C++ programs to include BTF */
#ifdef __cplusplus
extern "C" {
#endif
#include "UFconfig.h"
int btf_maxtrans /* returns # of columns matched */
(
/* --- input, not modified: --- */
int nrow, /* A is nrow-by-ncol in compressed column form */
int ncol,
int Ap [ ], /* size ncol+1 */
int Ai [ ], /* size nz = Ap [ncol] */
double maxwork, /* maximum amount of work to do is maxwork*nnz(A); no limit
* if <= 0 */
/* --- output, not defined on input --- */
double *work, /* work = -1 if maxwork > 0 and the total work performed
* reached the maximum of maxwork*nnz(A).
* Otherwise, work = the total work performed. */
int Match [ ], /* size nrow. Match [i] = j if column j matched to row i
* (see above for the singular-matrix case) */
/* --- workspace, not defined on input or output --- */
int Work [ ] /* size 5*ncol */
) ;
/* long integer version (all "int" parameters become "UF_long") */
UF_long btf_l_maxtrans (UF_long, UF_long, UF_long *, UF_long *, double,
double *, UF_long *, UF_long *) ;
/* ========================================================================== */
/* === BTF_STRONGCOMP ======================================================= */
/* ========================================================================== */
/* BTF_STRONGCOMP finds the strongly connected components of a graph, returning
* a symmetric permutation. The matrix A must be square, and is provided on
* input in compressed-column form (see BTF_MAXTRANS, above). The diagonal of
* the input matrix A (or A*Q if Q is provided on input) is ignored.
*
* If Q is not NULL on input, then the strongly connected components of A*Q are
* found. Q may be flagged on input, where Q[k] < 0 denotes a flagged column k.
* The permutation is j = BTF_UNFLIP (Q [k]). On output, Q is modified (the
* flags are preserved) so that P*A*Q is in block upper triangular form.
*
* If Q is NULL, then the permutation P is returned so that P*A*P' is in upper
* block triangular form.
*
* The vector R gives the block boundaries, where block b is in rows/columns
* R[b] to R[b+1]-1 of the permuted matrix, and where b ranges from 1 to the
* number of strongly connected components found.
*/
int btf_strongcomp /* return # of strongly connected components */
(
/* input, not modified: */
int n, /* A is n-by-n in compressed column form */
int Ap [ ], /* size n+1 */
int Ai [ ], /* size nz = Ap [n] */
/* optional input, modified (if present) on output: */
int Q [ ], /* size n, input column permutation */
/* output, not defined on input */
int P [ ], /* size n. P [k] = j if row and column j are kth row/col
* in permuted matrix. */
int R [ ], /* size n+1. block b is in rows/cols R[b] ... R[b+1]-1 */
/* workspace, not defined on input or output */
int Work [ ] /* size 4n */
) ;
UF_long btf_l_strongcomp (UF_long, UF_long *, UF_long *, UF_long *, UF_long *,
UF_long *, UF_long *) ;
/* ========================================================================== */
/* === BTF_ORDER ============================================================ */
/* ========================================================================== */
/* BTF_ORDER permutes a square matrix into upper block triangular form. It
* does this by first finding a maximum matching (or perhaps a limited matching
* if the work is limited), via the btf_maxtrans function. If a complete
* matching is not found, BTF_ORDER completes the permutation, but flags the
* columns of P*A*Q to denote which columns are not matched. If the matrix is
* structurally rank deficient, some of the entries on the diagonal of the
* permuted matrix will be zero. BTF_ORDER then calls btf_strongcomp to find
* the strongly-connected components.
*
* On output, P and Q are the row and column permutations, where i = P[k] if
* row i of A is the kth row of P*A*Q, and j = BTF_UNFLIP(Q[k]) if column j of
* A is the kth column of P*A*Q. If Q[k] < 0, then the (k,k)th entry in P*A*Q
* is structurally zero.
*
* The vector R gives the block boundaries, where block b is in rows/columns
* R[b] to R[b+1]-1 of the permuted matrix, and where b ranges from 1 to the
* number of strongly connected components found.
*/
int btf_order /* returns number of blocks found */
(
/* --- input, not modified: --- */
int n, /* A is n-by-n in compressed column form */
int Ap [ ], /* size n+1 */
int Ai [ ], /* size nz = Ap [n] */
double maxwork, /* do at most maxwork*nnz(A) work in the maximum
* transversal; no limit if <= 0 */
/* --- output, not defined on input --- */
double *work, /* return value from btf_maxtrans */
int P [ ], /* size n, row permutation */
int Q [ ], /* size n, column permutation */
int R [ ], /* size n+1. block b is in rows/cols R[b] ... R[b+1]-1 */
int *nmatch, /* # nonzeros on diagonal of P*A*Q */
/* --- workspace, not defined on input or output --- */
int Work [ ] /* size 5n */
) ;
UF_long btf_l_order (UF_long, UF_long *, UF_long *, double , double *,
UF_long *, UF_long *, UF_long *, UF_long *, UF_long *) ;
/* ========================================================================== */
/* === BTF marking of singular columns ====================================== */
/* ========================================================================== */
/* BTF_FLIP is a "negation about -1", and is used to mark an integer j
* that is normally non-negative. BTF_FLIP (-1) is -1. BTF_FLIP of
* a number > -1 is negative, and BTF_FLIP of a number < -1 is positive.
* BTF_FLIP (BTF_FLIP (j)) = j for all integers j. UNFLIP (j) acts
* like an "absolute value" operation, and is always >= -1. You can test
* whether or not an integer j is "flipped" with the BTF_ISFLIPPED (j)
* macro.
*/
#define BTF_FLIP(j) (-(j)-2)
#define BTF_ISFLIPPED(j) ((j) < -1)
#define BTF_UNFLIP(j) ((BTF_ISFLIPPED (j)) ? BTF_FLIP (j) : (j))
/* ========================================================================== */
/* === BTF version ========================================================== */
/* ========================================================================== */
/* All versions of BTF include these definitions.
* As an example, to test if the version you are using is 1.2 or later:
*
* if (BTF_VERSION >= BTF_VERSION_CODE (1,2)) ...
*
* This also works during compile-time:
*
* #if (BTF >= BTF_VERSION_CODE (1,2))
* printf ("This is version 1.2 or later\n") ;
* #else
* printf ("This is an early version\n") ;
* #endif
*/
#define BTF_DATE "Dec 7, 2011"
#define BTF_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
#define BTF_MAIN_VERSION 1
#define BTF_SUB_VERSION 1
#define BTF_SUBSUB_VERSION 3
#define BTF_VERSION BTF_VERSION_CODE(BTF_MAIN_VERSION,BTF_SUB_VERSION)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -288,6 +288,11 @@ struct CKTcircuit {
NGHASHPTR DEVnameHash;
NGHASHPTR MODnameHash;
#ifdef KLU
unsigned int CKTkluMODE:1 ;
#endif
};

View File

@ -0,0 +1,255 @@
/* ========================================================================== */
/* === colamd/symamd prototypes and definitions ============================= */
/* ========================================================================== */
/* COLAMD / SYMAMD include file
You must include this file (colamd.h) in any routine that uses colamd,
symamd, or the related macros and definitions.
Authors:
The authors of the code itself are Stefan I. Larimore and Timothy A.
Davis (davis at cise.ufl.edu), University of Florida. The algorithm was
developed in collaboration with John Gilbert, Xerox PARC, and Esmond
Ng, Oak Ridge National Laboratory.
Acknowledgements:
This work was supported by the National Science Foundation, under
grants DMS-9504974 and DMS-9803599.
Notice:
Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
Permission is hereby granted to use, copy, modify, and/or distribute
this program, provided that the Copyright, this License, and the
Availability of the original version is retained on all copies and made
accessible to the end-user of any code or package that includes COLAMD
or any modified version of COLAMD.
Availability:
The colamd/symamd library is available at
http://www.cise.ufl.edu/research/sparse/colamd/
This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.h
file. It is required by the colamd.c, colamdmex.c, and symamdmex.c
files, and by any C code that calls the routines whose prototypes are
listed below, or that uses the colamd/symamd definitions listed below.
*/
#ifndef COLAMD_H
#define COLAMD_H
/* make it easy for C++ programs to include COLAMD */
#ifdef __cplusplus
extern "C" {
#endif
/* ========================================================================== */
/* === Include files ======================================================== */
/* ========================================================================== */
#include <stdlib.h>
/* ========================================================================== */
/* === COLAMD version ======================================================= */
/* ========================================================================== */
/* COLAMD Version 2.4 and later will include the following definitions.
* As an example, to test if the version you are using is 2.4 or later:
*
* #ifdef COLAMD_VERSION
* if (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) ...
* #endif
*
* This also works during compile-time:
*
* #if defined(COLAMD_VERSION) && (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4))
* printf ("This is version 2.4 or later\n") ;
* #else
* printf ("This is an early version\n") ;
* #endif
*
* Versions 2.3 and earlier of COLAMD do not include a #define'd version number.
*/
#define COLAMD_DATE "Dec 7, 2011"
#define COLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
#define COLAMD_MAIN_VERSION 2
#define COLAMD_SUB_VERSION 7
#define COLAMD_SUBSUB_VERSION 4
#define COLAMD_VERSION \
COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION,COLAMD_SUB_VERSION)
/* ========================================================================== */
/* === Knob and statistics definitions ====================================== */
/* ========================================================================== */
/* size of the knobs [ ] array. Only knobs [0..1] are currently used. */
#define COLAMD_KNOBS 20
/* number of output statistics. Only stats [0..6] are currently used. */
#define COLAMD_STATS 20
/* knobs [0] and stats [0]: dense row knob and output statistic. */
#define COLAMD_DENSE_ROW 0
/* knobs [1] and stats [1]: dense column knob and output statistic. */
#define COLAMD_DENSE_COL 1
/* knobs [2]: aggressive absorption */
#define COLAMD_AGGRESSIVE 2
/* stats [2]: memory defragmentation count output statistic */
#define COLAMD_DEFRAG_COUNT 2
/* stats [3]: colamd status: zero OK, > 0 warning or notice, < 0 error */
#define COLAMD_STATUS 3
/* stats [4..6]: error info, or info on jumbled columns */
#define COLAMD_INFO1 4
#define COLAMD_INFO2 5
#define COLAMD_INFO3 6
/* error codes returned in stats [3]: */
#define COLAMD_OK (0)
#define COLAMD_OK_BUT_JUMBLED (1)
#define COLAMD_ERROR_A_not_present (-1)
#define COLAMD_ERROR_p_not_present (-2)
#define COLAMD_ERROR_nrow_negative (-3)
#define COLAMD_ERROR_ncol_negative (-4)
#define COLAMD_ERROR_nnz_negative (-5)
#define COLAMD_ERROR_p0_nonzero (-6)
#define COLAMD_ERROR_A_too_small (-7)
#define COLAMD_ERROR_col_length_negative (-8)
#define COLAMD_ERROR_row_index_out_of_bounds (-9)
#define COLAMD_ERROR_out_of_memory (-10)
#define COLAMD_ERROR_internal_error (-999)
/* ========================================================================== */
/* === Prototypes of user-callable routines ================================= */
/* ========================================================================== */
/* define UF_long */
#include "UFconfig.h"
size_t colamd_recommended /* returns recommended value of Alen, */
/* or 0 if input arguments are erroneous */
(
int nnz, /* nonzeros in A */
int n_row, /* number of rows in A */
int n_col /* number of columns in A */
) ;
size_t colamd_l_recommended /* returns recommended value of Alen, */
/* or 0 if input arguments are erroneous */
(
UF_long nnz, /* nonzeros in A */
UF_long n_row, /* number of rows in A */
UF_long n_col /* number of columns in A */
) ;
void colamd_set_defaults /* sets default parameters */
( /* knobs argument is modified on output */
double knobs [COLAMD_KNOBS] /* parameter settings for colamd */
) ;
void colamd_l_set_defaults /* sets default parameters */
( /* knobs argument is modified on output */
double knobs [COLAMD_KNOBS] /* parameter settings for colamd */
) ;
int colamd /* returns (1) if successful, (0) otherwise*/
( /* A and p arguments are modified on output */
int n_row, /* number of rows in A */
int n_col, /* number of columns in A */
int Alen, /* size of the array A */
int A [], /* row indices of A, of size Alen */
int p [], /* column pointers of A, of size n_col+1 */
double knobs [COLAMD_KNOBS],/* parameter settings for colamd */
int stats [COLAMD_STATS] /* colamd output statistics and error codes */
) ;
UF_long colamd_l /* returns (1) if successful, (0) otherwise*/
( /* A and p arguments are modified on output */
UF_long n_row, /* number of rows in A */
UF_long n_col, /* number of columns in A */
UF_long Alen, /* size of the array A */
UF_long A [], /* row indices of A, of size Alen */
UF_long p [], /* column pointers of A, of size n_col+1 */
double knobs [COLAMD_KNOBS],/* parameter settings for colamd */
UF_long stats [COLAMD_STATS]/* colamd output statistics and error codes */
) ;
int symamd /* return (1) if OK, (0) otherwise */
(
int n, /* number of rows and columns of A */
int A [], /* row indices of A */
int p [], /* column pointers of A */
int perm [], /* output permutation, size n_col+1 */
double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */
int stats [COLAMD_STATS], /* output statistics and error codes */
void * (*allocate) (size_t, size_t),
/* pointer to calloc (ANSI C) or */
/* mxCalloc (for MATLAB mexFunction) */
void (*release) (void *)
/* pointer to free (ANSI C) or */
/* mxFree (for MATLAB mexFunction) */
) ;
UF_long symamd_l /* return (1) if OK, (0) otherwise */
(
UF_long n, /* number of rows and columns of A */
UF_long A [], /* row indices of A */
UF_long p [], /* column pointers of A */
UF_long perm [], /* output permutation, size n_col+1 */
double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */
UF_long stats [COLAMD_STATS], /* output statistics and error codes */
void * (*allocate) (size_t, size_t),
/* pointer to calloc (ANSI C) or */
/* mxCalloc (for MATLAB mexFunction) */
void (*release) (void *)
/* pointer to free (ANSI C) or */
/* mxFree (for MATLAB mexFunction) */
) ;
void colamd_report
(
int stats [COLAMD_STATS]
) ;
void colamd_l_report
(
UF_long stats [COLAMD_STATS]
) ;
void symamd_report
(
int stats [COLAMD_STATS]
) ;
void symamd_l_report
(
UF_long stats [COLAMD_STATS]
) ;
#ifndef EXTERN
#define EXTERN extern
#endif
EXTERN int (*colamd_printf) (const char *, ...) ;
#ifdef __cplusplus
}
#endif
#endif /* COLAMD_H */

View File

@ -114,6 +114,15 @@ typedef struct SPICEdev {
int *DEVinstSize; /* size of an instance */
int *DEVmodSize; /* size of a model */
#ifdef KLU
int (*DEVbindCSC)(GENmodel *, CKTcircuit *) ;
/* routine to convert Sparse linked list to Real CSC array */
int (*DEVbindCSCComplex)(GENmodel *, CKTcircuit *) ;
/* routine to convert Real CSC array to Complex CSC array */
int (*DEVbindCSCComplexToReal)(GENmodel *, CKTcircuit *) ;
/* routine to convert Complex CSC array to Real CSC array */
#endif
} SPICEdev; /* instance of structure for each possible type of device */

831
src/include/ngspice/klu.h Normal file
View File

@ -0,0 +1,831 @@
/* ========================================================================== */
/* === klu include file ===================================================== */
/* ========================================================================== */
/* Include file for user programs that call klu_* routines */
#ifndef _KLU_H
#define _KLU_H
/* make it easy for C++ programs to include KLU */
#ifdef __cplusplus
extern "C" {
#endif
#include "amd.h"
#include "colamd.h"
#include "btf.h"
/* -------------------------------------------------------------------------- */
/* Symbolic object - contains the pre-ordering computed by klu_analyze */
/* -------------------------------------------------------------------------- */
typedef struct
{
/* A (P,Q) is in upper block triangular form. The kth block goes from
* row/col index R [k] to R [k+1]-1. The estimated number of nonzeros
* in the L factor of the kth block is Lnz [k].
*/
/* only computed if the AMD ordering is chosen: */
double symmetry ; /* symmetry of largest block */
double est_flops ; /* est. factorization flop count */
double lnz, unz ; /* estimated nz in L and U, including diagonals */
double *Lnz ; /* size n, but only Lnz [0..nblocks-1] is used */
/* computed for all orderings: */
int
n, /* input matrix A is n-by-n */
nz, /* # entries in input matrix */
*P, /* size n */
*Q, /* size n */
*R, /* size n+1, but only R [0..nblocks] is used */
nzoff, /* nz in off-diagonal blocks */
nblocks, /* number of blocks */
maxblock, /* size of largest block */
ordering, /* ordering used (AMD, COLAMD, or GIVEN) */
do_btf ; /* whether or not BTF preordering was requested */
/* only computed if BTF preordering requested */
int structural_rank ; /* 0 to n-1 if the matrix is structurally rank
* deficient. -1 if not computed. n if the matrix has
* full structural rank */
} klu_symbolic ;
typedef struct /* 64-bit version (otherwise same as above) */
{
double symmetry, est_flops, lnz, unz ;
double *Lnz ;
UF_long n, nz, *P, *Q, *R, nzoff, nblocks, maxblock, ordering, do_btf,
structural_rank ;
} klu_l_symbolic ;
/* -------------------------------------------------------------------------- */
/* Numeric object - contains the factors computed by klu_factor */
/* -------------------------------------------------------------------------- */
typedef struct
{
/* LU factors of each block, the pivot row permutation, and the
* entries in the off-diagonal blocks */
int n ; /* A is n-by-n */
int nblocks ; /* number of diagonal blocks */
int lnz ; /* actual nz in L, including diagonal */
int unz ; /* actual nz in U, including diagonal */
int max_lnz_block ; /* max actual nz in L in any one block, incl. diag */
int max_unz_block ; /* max actual nz in U in any one block, incl. diag */
int *Pnum ; /* size n. final pivot permutation */
int *Pinv ; /* size n. inverse of final pivot permutation */
/* LU factors of each block */
int *Lip ; /* size n. pointers into LUbx[block] for L */
int *Uip ; /* size n. pointers into LUbx[block] for U */
int *Llen ; /* size n. Llen [k] = # of entries in kth column of L */
int *Ulen ; /* size n. Ulen [k] = # of entries in kth column of U */
void **LUbx ; /* L and U indices and entries (excl. diagonal of U) */
size_t *LUsize ; /* size of each LUbx [block], in sizeof (Unit) */
void *Udiag ; /* diagonal of U */
/* scale factors; can be NULL if no scaling */
double *Rs ; /* size n. Rs [i] is scale factor for row i */
/* permanent workspace for factorization and solve */
size_t worksize ; /* size (in bytes) of Work */
void *Work ; /* workspace */
void *Xwork ; /* alias into Numeric->Work */
int *Iwork ; /* alias into Numeric->Work */
/* off-diagonal entries in a conventional compressed-column sparse matrix */
int *Offp ; /* size n+1, column pointers */
int *Offi ; /* size nzoff, row indices */
void *Offx ; /* size nzoff, numerical values */
int nzoff ;
} klu_numeric ;
typedef struct /* 64-bit version (otherwise same as above) */
{
UF_long n, nblocks, lnz, unz, max_lnz_block, max_unz_block, *Pnum, *Pinv,
*Lip, *Uip, *Llen, *Ulen ;
void **LUbx ;
size_t *LUsize ;
void *Udiag ;
double *Rs ;
size_t worksize ;
void *Work, *Xwork ;
UF_long *Iwork ;
UF_long *Offp, *Offi ;
void *Offx ;
UF_long nzoff ;
} klu_l_numeric ;
/* -------------------------------------------------------------------------- */
/* KLU control parameters and statistics */
/* -------------------------------------------------------------------------- */
/* Common->status values */
#define KLU_OK 0
#define KLU_SINGULAR (1) /* status > 0 is a warning, not an error */
#define KLU_OUT_OF_MEMORY (-2)
#define KLU_INVALID (-3)
#define KLU_TOO_LARGE (-4) /* integer overflow has occured */
typedef struct klu_common_struct
{
/* ---------------------------------------------------------------------- */
/* parameters */
/* ---------------------------------------------------------------------- */
double tol ; /* pivot tolerance for diagonal preference */
double memgrow ; /* realloc memory growth size for LU factors */
double initmem_amd ; /* init. memory size with AMD: c*nnz(L) + n */
double initmem ; /* init. memory size: c*nnz(A) + n */
double maxwork ; /* maxwork for BTF, <= 0 if no limit */
int btf ; /* use BTF pre-ordering, or not */
int ordering ; /* 0: AMD, 1: COLAMD, 2: user P and Q,
* 3: user function */
int scale ; /* row scaling: -1: none (and no error check),
* 0: none, 1: sum, 2: max */
/* memory management routines */
void *(*malloc_memory) (size_t) ; /* pointer to malloc */
void *(*realloc_memory) (void *, size_t) ; /* pointer to realloc */
void (*free_memory) (void *) ; /* pointer to free */
void *(*calloc_memory) (size_t, size_t) ; /* pointer to calloc */
/* pointer to user ordering function */
int (*user_order) (int, int *, int *, int *, struct klu_common_struct *) ;
/* pointer to user data, passed unchanged as the last parameter to the
* user ordering function (optional, the user function need not use this
* information). */
void *user_data ;
int halt_if_singular ; /* how to handle a singular matrix:
* FALSE: keep going. Return a Numeric object with a zero U(k,k). A
* divide-by-zero may occur when computing L(:,k). The Numeric object
* can be passed to klu_solve (a divide-by-zero will occur). It can
* also be safely passed to klu_refactor.
* TRUE: stop quickly. klu_factor will free the partially-constructed
* Numeric object. klu_refactor will not free it, but will leave the
* numerical values only partially defined. This is the default. */
/* ---------------------------------------------------------------------- */
/* statistics */
/* ---------------------------------------------------------------------- */
int status ; /* KLU_OK if OK, < 0 if error */
int nrealloc ; /* # of reallocations of L and U */
int structural_rank ; /* 0 to n-1 if the matrix is structurally rank
* deficient (as determined by maxtrans). -1 if not computed. n if the
* matrix has full structural rank. This is computed by klu_analyze
* if a BTF preordering is requested. */
int numerical_rank ; /* First k for which a zero U(k,k) was found,
* if the matrix was singular (in the range 0 to n-1). n if the matrix
* has full rank. This is not a true rank-estimation. It just reports
* where the first zero pivot was found. -1 if not computed.
* Computed by klu_factor and klu_refactor. */
int singular_col ; /* n if the matrix is not singular. If in the
* range 0 to n-1, this is the column index of the original matrix A that
* corresponds to the column of U that contains a zero diagonal entry.
* -1 if not computed. Computed by klu_factor and klu_refactor. */
int noffdiag ; /* # of off-diagonal pivots, -1 if not computed */
double flops ; /* actual factorization flop count, from klu_flops */
double rcond ; /* crude reciprocal condition est., from klu_rcond */
double condest ; /* accurate condition est., from klu_condest */
double rgrowth ; /* reciprocal pivot rgrowth, from klu_rgrowth */
double work ; /* actual work done in BTF, in klu_analyze */
size_t memusage ; /* current memory usage, in bytes */
size_t mempeak ; /* peak memory usage, in bytes */
} klu_common ;
typedef struct klu_l_common_struct /* 64-bit version (otherwise same as above)*/
{
double tol, memgrow, initmem_amd, initmem, maxwork ;
UF_long btf, ordering, scale ;
void *(*malloc_memory) (size_t) ;
void *(*realloc_memory) (void *, size_t) ;
void (*free_memory) (void *) ;
void *(*calloc_memory) (size_t, size_t) ;
UF_long (*user_order) (UF_long, UF_long *, UF_long *, UF_long *,
struct klu_l_common_struct *) ;
void *user_data ;
UF_long halt_if_singular ;
UF_long status, nrealloc, structural_rank, numerical_rank, singular_col,
noffdiag ;
double flops, rcond, condest, rgrowth, work ;
size_t memusage, mempeak ;
} klu_l_common ;
/* -------------------------------------------------------------------------- */
/* klu_defaults: sets default control parameters */
/* -------------------------------------------------------------------------- */
int klu_defaults
(
klu_common *Common
) ;
UF_long klu_l_defaults (klu_l_common *Common) ;
/* -------------------------------------------------------------------------- */
/* klu_analyze: orders and analyzes a matrix */
/* -------------------------------------------------------------------------- */
/* Order the matrix with BTF (or not), then order each block with AMD, COLAMD,
* a natural ordering, or with a user-provided ordering function */
klu_symbolic *klu_analyze
(
/* inputs, not modified */
int n, /* A is n-by-n */
int Ap [ ], /* size n+1, column pointers */
int Ai [ ], /* size nz, row indices */
klu_common *Common
) ;
klu_l_symbolic *klu_l_analyze (UF_long, UF_long *, UF_long *,
klu_l_common *Common) ;
/* -------------------------------------------------------------------------- */
/* klu_analyze_given: analyzes a matrix using given P and Q */
/* -------------------------------------------------------------------------- */
/* Order the matrix with BTF (or not), then use natural or given ordering
* P and Q on the blocks. P and Q are interpretted as identity
* if NULL. */
klu_symbolic *klu_analyze_given
(
/* inputs, not modified */
int n, /* A is n-by-n */
int Ap [ ], /* size n+1, column pointers */
int Ai [ ], /* size nz, row indices */
int P [ ], /* size n, user's row permutation (may be NULL) */
int Q [ ], /* size n, user's column permutation (may be NULL) */
klu_common *Common
) ;
klu_l_symbolic *klu_l_analyze_given (UF_long, UF_long *, UF_long *, UF_long *,
UF_long *, klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* klu_factor: factors a matrix using the klu_analyze results */
/* -------------------------------------------------------------------------- */
klu_numeric *klu_factor /* returns KLU_OK if OK, < 0 if error */
(
/* inputs, not modified */
int Ap [ ], /* size n+1, column pointers */
int Ai [ ], /* size nz, row indices */
double Ax [ ], /* size nz, numerical values */
klu_symbolic *Symbolic,
klu_common *Common
) ;
klu_numeric *klu_z_factor /* returns KLU_OK if OK, < 0 if error */
(
/* inputs, not modified */
int Ap [ ], /* size n+1, column pointers */
int Ai [ ], /* size nz, row indices */
double Ax [ ], /* size 2*nz, numerical values (real,imag pairs) */
klu_symbolic *Symbolic,
klu_common *Common
) ;
/* long / real version */
klu_l_numeric *klu_l_factor (UF_long *, UF_long *, double *, klu_l_symbolic *,
klu_l_common *) ;
/* long / complex version */
klu_l_numeric *klu_zl_factor (UF_long *, UF_long *, double *, klu_l_symbolic *,
klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* klu_solve: solves Ax=b using the Symbolic and Numeric objects */
/* -------------------------------------------------------------------------- */
int klu_solve
(
/* inputs, not modified */
klu_symbolic *Symbolic,
klu_numeric *Numeric,
int ldim, /* leading dimension of B */
int nrhs, /* number of right-hand-sides */
/* right-hand-side on input, overwritten with solution to Ax=b on output */
double B [ ], /* size ldim*nrhs */
klu_common *Common
) ;
int klu_z_solve
(
/* inputs, not modified */
klu_symbolic *Symbolic,
klu_numeric *Numeric,
int ldim, /* leading dimension of B */
int nrhs, /* number of right-hand-sides */
/* right-hand-side on input, overwritten with solution to Ax=b on output */
double B [ ], /* size 2*ldim*nrhs */
klu_common *Common
) ;
UF_long klu_l_solve (klu_l_symbolic *, klu_l_numeric *, UF_long, UF_long,
double *, klu_l_common *) ;
UF_long klu_zl_solve (klu_l_symbolic *, klu_l_numeric *, UF_long, UF_long,
double *, klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* klu_tsolve: solves A'x=b using the Symbolic and Numeric objects */
/* -------------------------------------------------------------------------- */
int klu_tsolve
(
/* inputs, not modified */
klu_symbolic *Symbolic,
klu_numeric *Numeric,
int ldim, /* leading dimension of B */
int nrhs, /* number of right-hand-sides */
/* right-hand-side on input, overwritten with solution to Ax=b on output */
double B [ ], /* size ldim*nrhs */
klu_common *Common
) ;
int klu_z_tsolve
(
/* inputs, not modified */
klu_symbolic *Symbolic,
klu_numeric *Numeric,
int ldim, /* leading dimension of B */
int nrhs, /* number of right-hand-sides */
/* right-hand-side on input, overwritten with solution to Ax=b on output */
double B [ ], /* size 2*ldim*nrhs */
int conj_solve, /* TRUE: conjugate solve, FALSE: solve A.'x=b */
klu_common *Common
) ;
UF_long klu_l_tsolve (klu_l_symbolic *, klu_l_numeric *, UF_long, UF_long,
double *, klu_l_common *) ;
UF_long klu_zl_tsolve (klu_l_symbolic *, klu_l_numeric *, UF_long, UF_long,
double *, UF_long, klu_l_common * ) ;
/* -------------------------------------------------------------------------- */
/* klu_refactor: refactorizes matrix with same ordering as klu_factor */
/* -------------------------------------------------------------------------- */
int klu_refactor /* return TRUE if successful, FALSE otherwise */
(
/* inputs, not modified */
int Ap [ ], /* size n+1, column pointers */
int Ai [ ], /* size nz, row indices */
double Ax [ ], /* size nz, numerical values */
klu_symbolic *Symbolic,
/* input, and numerical values modified on output */
klu_numeric *Numeric,
klu_common *Common
) ;
int klu_z_refactor /* return TRUE if successful, FALSE otherwise */
(
/* inputs, not modified */
int Ap [ ], /* size n+1, column pointers */
int Ai [ ], /* size nz, row indices */
double Ax [ ], /* size 2*nz, numerical values */
klu_symbolic *Symbolic,
/* input, and numerical values modified on output */
klu_numeric *Numeric,
klu_common *Common
) ;
UF_long klu_l_refactor (UF_long *, UF_long *, double *, klu_l_symbolic *,
klu_l_numeric *, klu_l_common *) ;
UF_long klu_zl_refactor (UF_long *, UF_long *, double *, klu_l_symbolic *,
klu_l_numeric *, klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* klu_free_symbolic: destroys the Symbolic object */
/* -------------------------------------------------------------------------- */
int klu_free_symbolic
(
klu_symbolic **Symbolic,
klu_common *Common
) ;
UF_long klu_l_free_symbolic (klu_l_symbolic **, klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* klu_free_numeric: destroys the Numeric object */
/* -------------------------------------------------------------------------- */
/* Note that klu_free_numeric and klu_z_free_numeric are identical; each can
* free both kinds of Numeric objects (real and complex) */
int klu_free_numeric
(
klu_numeric **Numeric,
klu_common *Common
) ;
int klu_z_free_numeric
(
klu_numeric **Numeric,
klu_common *Common
) ;
UF_long klu_l_free_numeric (klu_l_numeric **, klu_l_common *) ;
UF_long klu_zl_free_numeric (klu_l_numeric **, klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* klu_sort: sorts the columns of the LU factorization */
/* -------------------------------------------------------------------------- */
/* this is not needed except for the MATLAB interface */
int klu_sort
(
/* inputs, not modified */
klu_symbolic *Symbolic,
/* input/output */
klu_numeric *Numeric,
klu_common *Common
) ;
int klu_z_sort
(
/* inputs, not modified */
klu_symbolic *Symbolic,
/* input/output */
klu_numeric *Numeric,
klu_common *Common
) ;
UF_long klu_l_sort (klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ;
UF_long klu_zl_sort (klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* klu_flops: determines # of flops performed in numeric factorzation */
/* -------------------------------------------------------------------------- */
int klu_flops
(
/* inputs, not modified */
klu_symbolic *Symbolic,
klu_numeric *Numeric,
/* input/output */
klu_common *Common
) ;
int klu_z_flops
(
/* inputs, not modified */
klu_symbolic *Symbolic,
klu_numeric *Numeric,
/* input/output */
klu_common *Common
) ;
UF_long klu_l_flops (klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ;
UF_long klu_zl_flops (klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* klu_rgrowth : compute the reciprocal pivot growth */
/* -------------------------------------------------------------------------- */
/* Pivot growth is computed after the input matrix is permuted, scaled, and
* off-diagonal entries pruned. This is because the LU factorization of each
* block takes as input the scaled diagonal blocks of the BTF form. The
* reciprocal pivot growth in column j of an LU factorization of a matrix C
* is the largest entry in C divided by the largest entry in U; then the overall
* reciprocal pivot growth is the smallest such value for all columns j. Note
* that the off-diagonal entries are not scaled, since they do not take part in
* the LU factorization of the diagonal blocks.
*
* In MATLAB notation:
*
* rgrowth = min (max (abs ((R \ A(p,q)) - F)) ./ max (abs (U))) */
int klu_rgrowth
(
int Ap [ ],
int Ai [ ],
double Ax [ ],
klu_symbolic *Symbolic,
klu_numeric *Numeric,
klu_common *Common /* Common->rgrowth = reciprocal pivot growth */
) ;
int klu_z_rgrowth
(
int Ap [ ],
int Ai [ ],
double Ax [ ],
klu_symbolic *Symbolic,
klu_numeric *Numeric,
klu_common *Common /* Common->rgrowth = reciprocal pivot growth */
) ;
UF_long klu_l_rgrowth (UF_long *, UF_long *, double *, klu_l_symbolic *,
klu_l_numeric *, klu_l_common *) ;
UF_long klu_zl_rgrowth (UF_long *, UF_long *, double *, klu_l_symbolic *,
klu_l_numeric *, klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* klu_condest */
/* -------------------------------------------------------------------------- */
/* Computes a reasonably accurate estimate of the 1-norm condition number, using
* Hager's method, as modified by Higham and Tisseur (same method as used in
* MATLAB's condest */
int klu_condest
(
int Ap [ ], /* size n+1, column pointers, not modified */
double Ax [ ], /* size nz = Ap[n], numerical values, not modified*/
klu_symbolic *Symbolic, /* symbolic analysis, not modified */
klu_numeric *Numeric, /* numeric factorization, not modified */
klu_common *Common /* result returned in Common->condest */
) ;
int klu_z_condest
(
int Ap [ ],
double Ax [ ], /* size 2*nz */
klu_symbolic *Symbolic,
klu_numeric *Numeric,
klu_common *Common /* result returned in Common->condest */
) ;
UF_long klu_l_condest (UF_long *, double *, klu_l_symbolic *, klu_l_numeric *,
klu_l_common *) ;
UF_long klu_zl_condest (UF_long *, double *, klu_l_symbolic *, klu_l_numeric *,
klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* klu_rcond: compute min(abs(diag(U))) / max(abs(diag(U))) */
/* -------------------------------------------------------------------------- */
int klu_rcond
(
klu_symbolic *Symbolic, /* input, not modified */
klu_numeric *Numeric, /* input, not modified */
klu_common *Common /* result in Common->rcond */
) ;
int klu_z_rcond
(
klu_symbolic *Symbolic, /* input, not modified */
klu_numeric *Numeric, /* input, not modified */
klu_common *Common /* result in Common->rcond */
) ;
UF_long klu_l_rcond (klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ;
UF_long klu_zl_rcond (klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* klu_scale */
/* -------------------------------------------------------------------------- */
int klu_scale /* return TRUE if successful, FALSE otherwise */
(
/* inputs, not modified */
int scale, /* <0: none, no error check; 0: none, 1: sum, 2: max */
int n,
int Ap [ ], /* size n+1, column pointers */
int Ai [ ], /* size nz, row indices */
double Ax [ ],
/* outputs, not defined on input */
double Rs [ ],
/* workspace, not defined on input or output */
int W [ ], /* size n, can be NULL */
klu_common *Common
) ;
int klu_z_scale /* return TRUE if successful, FALSE otherwise */
(
/* inputs, not modified */
int scale, /* <0: none, no error check; 0: none, 1: sum, 2: max */
int n,
int Ap [ ], /* size n+1, column pointers */
int Ai [ ], /* size nz, row indices */
double Ax [ ],
/* outputs, not defined on input */
double Rs [ ],
/* workspace, not defined on input or output */
int W [ ], /* size n, can be NULL */
klu_common *Common
) ;
UF_long klu_l_scale (UF_long, UF_long, UF_long *, UF_long *, double *,
double *, UF_long *, klu_l_common *) ;
UF_long klu_zl_scale (UF_long, UF_long, UF_long *, UF_long *, double *,
double *, UF_long *, klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* klu_extract */
/* -------------------------------------------------------------------------- */
int klu_extract /* returns TRUE if successful, FALSE otherwise */
(
/* inputs: */
klu_numeric *Numeric,
klu_symbolic *Symbolic,
/* outputs, either allocated on input, or ignored otherwise */
/* L */
int *Lp, /* size n+1 */
int *Li, /* size Numeric->lnz */
double *Lx, /* size Numeric->lnz */
/* U */
int *Up, /* size n+1 */
int *Ui, /* size Numeric->unz */
double *Ux, /* size Numeric->unz */
/* F */
int *Fp, /* size n+1 */
int *Fi, /* size Numeric->nzoff */
double *Fx, /* size Numeric->nzoff */
/* P, row permutation */
int *P, /* size n */
/* Q, column permutation */
int *Q, /* size n */
/* Rs, scale factors */
double *Rs, /* size n */
/* R, block boundaries */
int *R, /* size Symbolic->nblocks+1 (nblocks is at most n) */
klu_common *Common
) ;
int klu_z_extract /* returns TRUE if successful, FALSE otherwise */
(
/* inputs: */
klu_numeric *Numeric,
klu_symbolic *Symbolic,
/* outputs, all of which must be allocated on input */
/* L */
int *Lp, /* size n+1 */
int *Li, /* size nnz(L) */
double *Lx, /* size nnz(L) */
double *Lz, /* size nnz(L) for the complex case, ignored if real */
/* U */
int *Up, /* size n+1 */
int *Ui, /* size nnz(U) */
double *Ux, /* size nnz(U) */
double *Uz, /* size nnz(U) for the complex case, ignored if real */
/* F */
int *Fp, /* size n+1 */
int *Fi, /* size nnz(F) */
double *Fx, /* size nnz(F) */
double *Fz, /* size nnz(F) for the complex case, ignored if real */
/* P, row permutation */
int *P, /* size n */
/* Q, column permutation */
int *Q, /* size n */
/* Rs, scale factors */
double *Rs, /* size n */
/* R, block boundaries */
int *R, /* size Symbolic->nblocks+1 (nblocks is at most n) */
klu_common *Common
) ;
UF_long klu_l_extract (klu_l_numeric *, klu_l_symbolic *,
UF_long *, UF_long *, double *,
UF_long *, UF_long *, double *,
UF_long *, UF_long *, double *,
UF_long *, UF_long *, double *, UF_long *, klu_l_common *) ;
UF_long klu_zl_extract (klu_l_numeric *, klu_l_symbolic *,
UF_long *, UF_long *, double *, double *,
UF_long *, UF_long *, double *, double *,
UF_long *, UF_long *, double *, double *,
UF_long *, UF_long *, double *, UF_long *, klu_l_common *) ;
/* -------------------------------------------------------------------------- */
/* KLU memory management routines */
/* -------------------------------------------------------------------------- */
void *klu_malloc /* returns pointer to the newly malloc'd block */
(
/* ---- input ---- */
size_t n, /* number of items */
size_t size, /* size of each item */
/* --------------- */
klu_common *Common
) ;
void *klu_free /* always returns NULL */
(
/* ---- in/out --- */
void *p, /* block of memory to free */
size_t n, /* number of items */
size_t size, /* size of each item */
/* --------------- */
klu_common *Common
) ;
void *klu_realloc /* returns pointer to reallocated block */
(
/* ---- input ---- */
size_t nnew, /* requested # of items in reallocated block */
size_t nold, /* current size of block, in # of items */
size_t size, /* size of each item */
/* ---- in/out --- */
void *p, /* block of memory to realloc */
/* --------------- */
klu_common *Common
) ;
void *klu_l_malloc (size_t, size_t, klu_l_common *) ;
void *klu_l_free (void *, size_t, size_t, klu_l_common *) ;
void *klu_l_realloc (size_t, size_t, size_t, void *, klu_l_common *) ;
/* ========================================================================== */
/* === KLU version ========================================================== */
/* ========================================================================== */
/* All versions of KLU include these definitions.
* As an example, to test if the version you are using is 1.2 or later:
*
* if (KLU_VERSION >= KLU_VERSION_CODE (1,2)) ...
*
* This also works during compile-time:
*
* #if (KLU >= KLU_VERSION_CODE (1,2))
* printf ("This is version 1.2 or later\n") ;
* #else
* printf ("This is an early version\n") ;
* #endif
*/
#define KLU_DATE "Nov 30, 2009"
#define KLU_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
#define KLU_MAIN_VERSION 1
#define KLU_SUB_VERSION 1
#define KLU_SUBSUB_VERSION 1
#define KLU_VERSION KLU_VERSION_CODE(KLU_MAIN_VERSION,KLU_SUB_VERSION)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -120,6 +120,10 @@ typedef struct {
#define OPT_NOOPAC 68
#ifdef KLU
#define OPT_SPARSE 69
#endif
#ifdef XSPICE
/* gtri - begin - wbk - add new options */
#define OPT_ENH_NOOPALTER 100

View File

@ -1,8 +1,12 @@
#ifndef ngspice_SMPDEFS_H
#define ngspice_SMPDEFS_H
/* Typedef removed by Francesco Lannutti (2012-02) to create the new SMPmatrix structure */
/*
typedef struct MatrixFrame SMPmatrix;
typedef struct MatrixElement SMPelement;
*/
typedef struct MatrixFrame MatrixFrame;
typedef struct MatrixElement *SMPelement;
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
@ -14,6 +18,44 @@ Modified: 2000 AlansFixes
#include <math.h>
#include "ngspice/complex.h"
#ifdef KLU
#include "ngspice/klu.h"
#include "ngspice/spmatrix.h"
#endif
/* SMPmatrix structure - Francesco Lannutti (2012-02) */
typedef struct sSMPmatrix {
MatrixFrame *SPmatrix ; /* pointer to sparse matrix */
#ifdef KLU
klu_common *CKTkluCommon ; /* KLU common object */
klu_symbolic *CKTkluSymbolic ; /* KLU symbolic object */
klu_numeric *CKTkluNumeric ; /* KLU numeric object */
int *CKTkluAp ; /* KLU column pointer */
int *CKTkluAi ; /* KLU row pointer */
double *CKTkluAx ; /* KLU Real Elements */
double *CKTkluAx_Complex ; /* KLU Complex Elements */
int CKTkluMatrixIsComplex ; /* KLU Matrix Is Complex Flag */
#define CKTkluMatrixReal 0 /* KLU Matrix Real definition */
#define CKTkluMatrixComplex 1 /* KLU Matrix Complex definition */
double *CKTkluIntermediate ; /* KLU RHS Intermediate for Solve Real Step */
double *CKTkluIntermediate_Complex ; /* KLU iRHS Intermediate for Solve Complex Step */
BindElement *CKTbindStruct ; /* KLU - Sparse Binding Structure */
double **CKTdiag_CSC ; /* KLU pointer to diagonal element to perform Gmin */
int CKTkluN ; /* KLU N, copied */
int CKTklunz ; /* KLU nz, copied for AC Analysis */
unsigned int CKTkluMODE:1 ; /* KLU MODE parameter to enable KLU or not from the heuristic */
#define CKTkluON 1 /* KLU MODE ON definition */
#define CKTkluOFF 0 /* KLU MODE OFF definition */
#endif
} SMPmatrix ;
#ifdef KLU
void SMPmatrix_CSC (SMPmatrix *) ;
void SMPnnz (SMPmatrix *) ;
#endif
int SMPaddElt( SMPmatrix *, int , int , double );
double * SMPmakeElt( SMPmatrix * , int , int );
void SMPcClear( SMPmatrix *);
@ -27,7 +69,7 @@ void SMPcaSolve(SMPmatrix *Matrix, double RHS[], double iRHS[],
void SMPcSolve( SMPmatrix *, double [], double [], double [], double []);
void SMPsolve( SMPmatrix *, double [], double []);
int SMPmatSize( SMPmatrix *);
int SMPnewMatrix( SMPmatrix ** );
int SMPnewMatrix( SMPmatrix * );
void SMPdestroy( SMPmatrix *);
int SMPpreOrder( SMPmatrix *);
void SMPprint( SMPmatrix * , char *);

View File

@ -35,6 +35,8 @@
*/
/* Francesco Lannutti 2012-09 - NGSPICE Configuration File Inclusion */
#include "ngspice/config.h"
#ifndef spOKAY
@ -294,4 +296,20 @@ extern void spMultTransposed(MatrixPtr,spREAL*,spREAL*,spREAL*,spREAL*);
extern void spSolve( MatrixPtr, spREAL*, spREAL*, spREAL*, spREAL* );
extern void spSolveTransposed(MatrixPtr,spREAL*,spREAL*,spREAL*,spREAL*);
/* Francesco Lannutti - CSC Data Structure Conversion */
#ifdef KLU
typedef struct sBindElement {
double *Sparse ;
double *CSC ;
double *CSC_Complex ;
} BindElement ;
extern int WriteCol_original (MatrixPtr, int, spREAL *, spREAL *, int *, BindElement *, spREAL **) ;
extern int WriteCol_original_dump (MatrixPtr, int, spREAL *, int *) ;
extern void spMatrix_CSC (MatrixPtr, int *, int *, double *, double *, int, BindElement *, double **) ;
extern void spMatrix_CSC_dump (MatrixPtr, char *) ;
extern void spRHS_CSC_dump (spREAL *, char *, MatrixPtr) ;
#endif
/* ------------------------------------------------------ */
#endif /* spOKAY */

View File

@ -66,6 +66,11 @@ struct TSKtask {
double TSKabsDv; /* abs limit for iter-iter voltage change */
double TSKrelDv; /* rel limit for iter-iter voltage change */
unsigned int TSKnoopac:1; /* flag for no OP calculation before AC */
#ifdef KLU
unsigned int TSKkluMODE:1 ;
#endif
};
#endif

97
src/maths/KLU/Makefile.am Normal file
View File

@ -0,0 +1,97 @@
## Process this file with automake to produce Makefile.in
noinst_LTLIBRARIES = libKLU_real.la libKLU_complex.la libKLU.la
libKLU_real_la_SOURCES = \
amd_1.c \
amd_2.c \
amd_aat.c \
amd_control.c \
amd_defaults.c \
amd_dump.c \
amd_global.c \
amd_info.c \
amd_order.c \
amd_postorder.c \
amd_post_tree.c \
amd_preprocess.c \
amd_valid.c \
btf_maxtrans.c \
btf_order.c \
btf_strongcomp.c \
colamd.c \
colamd_global.c \
klu.c \
klu_analyze.c \
klu_analyze_given.c \
klu_defaults.c \
klu_diagnostics.c \
klu_dump.c \
klu_extract.c \
klu_factor.c \
klu_free_numeric.c \
klu_free_symbolic.c \
klu_kernel.c \
klu_memory.c \
klu_refactor.c \
klu_scale.c \
klu_solve.c \
klu_sort.c \
klu_tsolve.c
libKLU_real_la_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include
libKLU_complex_la_SOURCES = \
amd_1.c \
amd_2.c \
amd_aat.c \
amd_control.c \
amd_defaults.c \
amd_dump.c \
amd_global.c \
amd_info.c \
amd_order.c \
amd_postorder.c \
amd_post_tree.c \
amd_preprocess.c \
amd_valid.c \
btf_maxtrans.c \
btf_order.c \
btf_strongcomp.c \
colamd.c \
colamd_global.c \
klu.c \
klu_analyze.c \
klu_analyze_given.c \
klu_defaults.c \
klu_diagnostics.c \
klu_dump.c \
klu_extract.c \
klu_factor.c \
klu_free_numeric.c \
klu_free_symbolic.c \
klu_kernel.c \
klu_memory.c \
klu_refactor.c \
klu_scale.c \
klu_solve.c \
klu_sort.c \
klu_tsolve.c
libKLU_complex_la_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -DCOMPLEX
libKLU_la_SOURCES = \
klusmp.c
libKLU_la_LIBADD = \
libKLU_real.la \
libKLU_complex.la
libKLU_la_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include
MAINTAINERCLEANFILES = Makefile.in

181
src/maths/KLU/amd_1.c Normal file
View File

@ -0,0 +1,181 @@
/* ========================================================================= */
/* === AMD_1 =============================================================== */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.
*
* The n-by-n sparse matrix A can be unsymmetric. It is stored in MATLAB-style
* compressed-column form, with sorted row indices in each column, and no
* duplicate entries. Diagonal entries may be present, but they are ignored.
* Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].
* Ap [0] must be zero, and nz = Ap [n] is the number of entries in A. The
* size of the matrix, n, must be greater than or equal to zero.
*
* This routine must be preceded by a call to AMD_aat, which computes the
* number of entries in each row/column in A+A', excluding the diagonal.
* Len [j], on input, is the number of entries in row/column j of A+A'. This
* routine constructs the matrix A+A' and then calls AMD_2. No error checking
* is performed (this was done in AMD_valid).
*/
#include "amd_internal.h"
GLOBAL void AMD_1
(
Int n, /* n > 0 */
const Int Ap [ ], /* input of size n+1, not modified */
const Int Ai [ ], /* input of size nz = Ap [n], not modified */
Int P [ ], /* size n output permutation */
Int Pinv [ ], /* size n output inverse permutation */
Int Len [ ], /* size n input, undefined on output */
Int slen, /* slen >= sum (Len [0..n-1]) + 7n,
* ideally slen = 1.2 * sum (Len) + 8n */
Int S [ ], /* size slen workspace */
double Control [ ], /* input array of size AMD_CONTROL */
double Info [ ] /* output array of size AMD_INFO */
)
{
Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,
*Elen, *Degree, *s, *W, *Sp, *Tp ;
/* --------------------------------------------------------------------- */
/* construct the matrix for AMD_2 */
/* --------------------------------------------------------------------- */
ASSERT (n > 0) ;
iwlen = slen - 6*n ;
s = S ;
Pe = s ; s += n ;
Nv = s ; s += n ;
Head = s ; s += n ;
Elen = s ; s += n ;
Degree = s ; s += n ;
W = s ; s += n ;
Iw = s ; s += iwlen ;
ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
/* construct the pointers for A+A' */
Sp = Nv ; /* use Nv and W as workspace for Sp and Tp [ */
Tp = W ;
pfree = 0 ;
for (j = 0 ; j < n ; j++)
{
Pe [j] = pfree ;
Sp [j] = pfree ;
pfree += Len [j] ;
}
/* Note that this restriction on iwlen is slightly more restrictive than
* what is strictly required in AMD_2. AMD_2 can operate with no elbow
* room at all, but it will be very slow. For better performance, at
* least size-n elbow room is enforced. */
ASSERT (iwlen >= pfree + n) ;
#ifndef NDEBUG
for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;
#endif
for (k = 0 ; k < n ; k++)
{
AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k)) ;
p1 = Ap [k] ;
p2 = Ap [k+1] ;
/* construct A+A' */
for (p = p1 ; p < p2 ; )
{
/* scan the upper triangular part of A */
j = Ai [p] ;
ASSERT (j >= 0 && j < n) ;
if (j < k)
{
/* entry A (j,k) in the strictly upper triangular part */
ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;
Iw [Sp [j]++] = k ;
Iw [Sp [k]++] = j ;
p++ ;
}
else if (j == k)
{
/* skip the diagonal */
p++ ;
break ;
}
else /* j > k */
{
/* first entry below the diagonal */
break ;
}
/* scan lower triangular part of A, in column j until reaching
* row k. Start where last scan left off. */
ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
pj2 = Ap [j+1] ;
for (pj = Tp [j] ; pj < pj2 ; )
{
i = Ai [pj] ;
ASSERT (i >= 0 && i < n) ;
if (i < k)
{
/* A (i,j) is only in the lower part, not in upper */
ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
Iw [Sp [i]++] = j ;
Iw [Sp [j]++] = i ;
pj++ ;
}
else if (i == k)
{
/* entry A (k,j) in lower part and A (j,k) in upper */
pj++ ;
break ;
}
else /* i > k */
{
/* consider this entry later, when k advances to i */
break ;
}
}
Tp [j] = pj ;
}
Tp [k] = p ;
}
/* clean up, for remaining mismatched entries */
for (j = 0 ; j < n ; j++)
{
for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
{
i = Ai [pj] ;
ASSERT (i >= 0 && i < n) ;
/* A (i,j) is only in the lower part, not in upper */
ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
Iw [Sp [i]++] = j ;
Iw [Sp [j]++] = i ;
}
}
#ifndef NDEBUG
for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;
ASSERT (Sp [n-1] == pfree) ;
#endif
/* Tp and Sp no longer needed ] */
/* --------------------------------------------------------------------- */
/* order the matrix */
/* --------------------------------------------------------------------- */
AMD_2 (n, Pe, Iw, Len, iwlen, pfree,
Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;
}

1842
src/maths/KLU/amd_2.c Normal file

File diff suppressed because it is too large Load Diff

185
src/maths/KLU/amd_aat.c Normal file
View File

@ -0,0 +1,185 @@
/* ========================================================================= */
/* === AMD_aat ============================================================= */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* AMD_aat: compute the symmetry of the pattern of A, and count the number of
* nonzeros each column of A+A' (excluding the diagonal). Assumes the input
* matrix has no errors, with sorted columns and no duplicates
* (AMD_valid (n, n, Ap, Ai) must be AMD_OK, but this condition is not
* checked).
*/
#include "amd_internal.h"
GLOBAL size_t AMD_aat /* returns nz in A+A' */
(
Int n,
const Int Ap [ ],
const Int Ai [ ],
Int Len [ ], /* Len [j]: length of column j of A+A', excl diagonal*/
Int Tp [ ], /* workspace of size n */
double Info [ ]
)
{
Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ;
double sym ;
size_t nzaat ;
#ifndef NDEBUG
AMD_debug_init ("AMD AAT") ;
for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ;
ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
#endif
if (Info != (double *) NULL)
{
/* clear the Info array, if it exists */
for (i = 0 ; i < AMD_INFO ; i++)
{
Info [i] = EMPTY ;
}
Info [AMD_STATUS] = AMD_OK ;
}
for (k = 0 ; k < n ; k++)
{
Len [k] = 0 ;
}
nzdiag = 0 ;
nzboth = 0 ;
nz = Ap [n] ;
for (k = 0 ; k < n ; k++)
{
p1 = Ap [k] ;
p2 = Ap [k+1] ;
AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ;
/* construct A+A' */
for (p = p1 ; p < p2 ; )
{
/* scan the upper triangular part of A */
j = Ai [p] ;
if (j < k)
{
/* entry A (j,k) is in the strictly upper triangular part,
* add both A (j,k) and A (k,j) to the matrix A+A' */
Len [j]++ ;
Len [k]++ ;
AMD_DEBUG3 ((" upper ("ID","ID") ("ID","ID")\n", j,k, k,j));
p++ ;
}
else if (j == k)
{
/* skip the diagonal */
p++ ;
nzdiag++ ;
break ;
}
else /* j > k */
{
/* first entry below the diagonal */
break ;
}
/* scan lower triangular part of A, in column j until reaching
* row k. Start where last scan left off. */
ASSERT (Tp [j] != EMPTY) ;
ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
pj2 = Ap [j+1] ;
for (pj = Tp [j] ; pj < pj2 ; )
{
i = Ai [pj] ;
if (i < k)
{
/* A (i,j) is only in the lower part, not in upper.
* add both A (i,j) and A (j,i) to the matrix A+A' */
Len [i]++ ;
Len [j]++ ;
AMD_DEBUG3 ((" lower ("ID","ID") ("ID","ID")\n",
i,j, j,i)) ;
pj++ ;
}
else if (i == k)
{
/* entry A (k,j) in lower part and A (j,k) in upper */
pj++ ;
nzboth++ ;
break ;
}
else /* i > k */
{
/* consider this entry later, when k advances to i */
break ;
}
}
Tp [j] = pj ;
}
/* Tp [k] points to the entry just below the diagonal in column k */
Tp [k] = p ;
}
/* clean up, for remaining mismatched entries */
for (j = 0 ; j < n ; j++)
{
for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
{
i = Ai [pj] ;
/* A (i,j) is only in the lower part, not in upper.
* add both A (i,j) and A (j,i) to the matrix A+A' */
Len [i]++ ;
Len [j]++ ;
AMD_DEBUG3 ((" lower cleanup ("ID","ID") ("ID","ID")\n",
i,j, j,i)) ;
}
}
/* --------------------------------------------------------------------- */
/* compute the symmetry of the nonzero pattern of A */
/* --------------------------------------------------------------------- */
/* Given a matrix A, the symmetry of A is:
* B = tril (spones (A), -1) + triu (spones (A), 1) ;
* sym = nnz (B & B') / nnz (B) ;
* or 1 if nnz (B) is zero.
*/
if (nz == nzdiag)
{
sym = 1 ;
}
else
{
sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ;
}
nzaat = 0 ;
for (k = 0 ; k < n ; k++)
{
nzaat += Len [k] ;
}
AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = %g\n",
(double) nzaat)) ;
AMD_DEBUG1 ((" nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n",
nzboth, nz, nzdiag, sym)) ;
if (Info != (double *) NULL)
{
Info [AMD_STATUS] = AMD_OK ;
Info [AMD_N] = n ;
Info [AMD_NZ] = nz ;
Info [AMD_SYMMETRY] = sym ; /* symmetry of pattern of A */
Info [AMD_NZDIAG] = nzdiag ; /* nonzeros on diagonal of A */
Info [AMD_NZ_A_PLUS_AT] = nzaat ; /* nonzeros in A+A' */
}
return (nzaat) ;
}

View File

@ -0,0 +1,64 @@
/* ========================================================================= */
/* === AMD_control ========================================================= */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* User-callable. Prints the control parameters for AMD. See amd.h
* for details. If the Control array is not present, the defaults are
* printed instead.
*/
#include "amd_internal.h"
GLOBAL void AMD_control
(
double Control [ ]
)
{
double alpha ;
Int aggressive ;
if (Control != (double *) NULL)
{
alpha = Control [AMD_DENSE] ;
aggressive = Control [AMD_AGGRESSIVE] != 0 ;
}
else
{
alpha = AMD_DEFAULT_DENSE ;
aggressive = AMD_DEFAULT_AGGRESSIVE ;
}
PRINTF (("\nAMD version %d.%d.%d, %s: approximate minimum degree ordering\n"
" dense row parameter: %g\n", AMD_MAIN_VERSION, AMD_SUB_VERSION,
AMD_SUBSUB_VERSION, AMD_DATE, alpha)) ;
if (alpha < 0)
{
PRINTF ((" no rows treated as dense\n")) ;
}
else
{
PRINTF ((
" (rows with more than max (%g * sqrt (n), 16) entries are\n"
" considered \"dense\", and placed last in output permutation)\n",
alpha)) ;
}
if (aggressive)
{
PRINTF ((" aggressive absorption: yes\n")) ;
}
else
{
PRINTF ((" aggressive absorption: no\n")) ;
}
PRINTF ((" size of AMD integer: %d\n\n", sizeof (Int))) ;
}

View File

@ -0,0 +1,38 @@
/* ========================================================================= */
/* === AMD_defaults ======================================================== */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* User-callable. Sets default control parameters for AMD. See amd.h
* for details.
*/
#include "amd_internal.h"
/* ========================================================================= */
/* === AMD defaults ======================================================== */
/* ========================================================================= */
GLOBAL void AMD_defaults
(
double Control [ ]
)
{
Int i ;
if (Control != (double *) NULL)
{
for (i = 0 ; i < AMD_CONTROL ; i++)
{
Control [i] = 0 ;
}
Control [AMD_DENSE] = AMD_DEFAULT_DENSE ;
Control [AMD_AGGRESSIVE] = AMD_DEFAULT_AGGRESSIVE ;
}
}

180
src/maths/KLU/amd_dump.c Normal file
View File

@ -0,0 +1,180 @@
/* ========================================================================= */
/* === AMD_dump ============================================================ */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* Debugging routines for AMD. Not used if NDEBUG is not defined at compile-
* time (the default). See comments in amd_internal.h on how to enable
* debugging. Not user-callable.
*/
#include "amd_internal.h"
#ifndef NDEBUG
/* This global variable is present only when debugging */
GLOBAL Int AMD_debug = -999 ; /* default is no debug printing */
/* ========================================================================= */
/* === AMD_debug_init ====================================================== */
/* ========================================================================= */
/* Sets the debug print level, by reading the file debug.amd (if it exists) */
GLOBAL void AMD_debug_init ( char *s )
{
FILE *f ;
f = fopen ("debug.amd", "r") ;
if (f == (FILE *) NULL)
{
AMD_debug = -999 ;
}
else
{
fscanf (f, ID, &AMD_debug) ;
fclose (f) ;
}
if (AMD_debug >= 0)
{
printf ("%s: AMD_debug_init, D= "ID"\n", s, AMD_debug) ;
}
}
/* ========================================================================= */
/* === AMD_dump ============================================================ */
/* ========================================================================= */
/* Dump AMD's data structure, except for the hash buckets. This routine
* cannot be called when the hash buckets are non-empty.
*/
GLOBAL void AMD_dump (
Int n, /* A is n-by-n */
Int Pe [ ], /* pe [0..n-1]: index in iw of start of row i */
Int Iw [ ], /* workspace of size iwlen, iwlen [0..pfree-1]
* holds the matrix on input */
Int Len [ ], /* len [0..n-1]: length for row i */
Int iwlen, /* length of iw */
Int pfree, /* iw [pfree ... iwlen-1] is empty on input */
Int Nv [ ], /* nv [0..n-1] */
Int Next [ ], /* next [0..n-1] */
Int Last [ ], /* last [0..n-1] */
Int Head [ ], /* head [0..n-1] */
Int Elen [ ], /* size n */
Int Degree [ ], /* size n */
Int W [ ], /* size n */
Int nel
)
{
Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ;
if (AMD_debug < 0) return ;
ASSERT (pfree <= iwlen) ;
AMD_DEBUG3 (("\nAMD dump, pfree: "ID"\n", pfree)) ;
for (i = 0 ; i < n ; i++)
{
pe = Pe [i] ;
elen = Elen [i] ;
nv = Nv [i] ;
len = Len [i] ;
w = W [i] ;
if (elen >= EMPTY)
{
if (nv == 0)
{
AMD_DEBUG3 (("\nI "ID": nonprincipal: ", i)) ;
ASSERT (elen == EMPTY) ;
if (pe == EMPTY)
{
AMD_DEBUG3 ((" dense node\n")) ;
ASSERT (w == 1) ;
}
else
{
ASSERT (pe < EMPTY) ;
AMD_DEBUG3 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i])));
}
}
else
{
AMD_DEBUG3 (("\nI "ID": active principal supervariable:\n",i));
AMD_DEBUG3 ((" nv(i): "ID" Flag: %d\n", nv, (nv < 0))) ;
ASSERT (elen >= 0) ;
ASSERT (nv > 0 && pe >= 0) ;
p = pe ;
AMD_DEBUG3 ((" e/s: ")) ;
if (elen == 0) AMD_DEBUG3 ((" : ")) ;
ASSERT (pe + len <= pfree) ;
for (k = 0 ; k < len ; k++)
{
j = Iw [p] ;
AMD_DEBUG3 ((" "ID"", j)) ;
ASSERT (j >= 0 && j < n) ;
if (k == elen-1) AMD_DEBUG3 ((" : ")) ;
p++ ;
}
AMD_DEBUG3 (("\n")) ;
}
}
else
{
e = i ;
if (w == 0)
{
AMD_DEBUG3 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ;
ASSERT (nv > 0 && pe < 0) ;
AMD_DEBUG3 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ;
}
else
{
AMD_DEBUG3 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ;
ASSERT (nv > 0 && pe >= 0) ;
p = pe ;
AMD_DEBUG3 ((" : ")) ;
ASSERT (pe + len <= pfree) ;
for (k = 0 ; k < len ; k++)
{
j = Iw [p] ;
AMD_DEBUG3 ((" "ID"", j)) ;
ASSERT (j >= 0 && j < n) ;
p++ ;
}
AMD_DEBUG3 (("\n")) ;
}
}
}
/* this routine cannot be called when the hash buckets are non-empty */
AMD_DEBUG3 (("\nDegree lists:\n")) ;
if (nel >= 0)
{
cnt = 0 ;
for (deg = 0 ; deg < n ; deg++)
{
if (Head [deg] == EMPTY) continue ;
ilast = EMPTY ;
AMD_DEBUG3 ((ID": \n", deg)) ;
for (i = Head [deg] ; i != EMPTY ; i = Next [i])
{
AMD_DEBUG3 ((" "ID" : next "ID" last "ID" deg "ID"\n",
i, Next [i], Last [i], Degree [i])) ;
ASSERT (i >= 0 && i < n && ilast == Last [i] &&
deg == Degree [i]) ;
cnt += Nv [i] ;
ilast = i ;
}
AMD_DEBUG3 (("\n")) ;
}
ASSERT (cnt == n - nel) ;
}
}
#endif

View File

@ -0,0 +1,84 @@
/* ========================================================================= */
/* === amd_global ========================================================== */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
#include <stdlib.h>
#ifdef MATLAB_MEX_FILE
#include "mex.h"
#include "matrix.h"
#endif
#ifndef NULL
#define NULL 0
#endif
/* ========================================================================= */
/* === Default AMD memory manager ========================================== */
/* ========================================================================= */
/* The user can redefine these global pointers at run-time to change the memory
* manager used by AMD. AMD only uses malloc and free; realloc and calloc are
* include for completeness, in case another package wants to use the same
* memory manager as AMD.
*
* If compiling as a MATLAB mexFunction, the default memory manager is mxMalloc.
* You can also compile AMD as a standard ANSI-C library and link a mexFunction
* against it, and then redefine these pointers at run-time, in your
* mexFunction.
*
* If -DNMALLOC is defined at compile-time, no memory manager is specified at
* compile-time. You must then define these functions at run-time, before
* calling AMD, for AMD to work properly.
*/
#ifndef NMALLOC
#ifdef MATLAB_MEX_FILE
/* MATLAB mexFunction: */
void *(*amd_malloc) (size_t) = mxMalloc ;
void (*amd_free) (void *) = mxFree ;
void *(*amd_realloc) (void *, size_t) = mxRealloc ;
void *(*amd_calloc) (size_t, size_t) = mxCalloc ;
#else
/* standard ANSI-C: */
void *(*amd_malloc) (size_t) = malloc ;
void (*amd_free) (void *) = free ;
void *(*amd_realloc) (void *, size_t) = realloc ;
void *(*amd_calloc) (size_t, size_t) = calloc ;
#endif
#else
/* no memory manager defined at compile-time; you MUST define one at run-time */
void *(*amd_malloc) (size_t) = NULL ;
void (*amd_free) (void *) = NULL ;
void *(*amd_realloc) (void *, size_t) = NULL ;
void *(*amd_calloc) (size_t, size_t) = NULL ;
#endif
/* ========================================================================= */
/* === Default AMD printf routine ========================================== */
/* ========================================================================= */
/* The user can redefine this global pointer at run-time to change the printf
* routine used by AMD. If NULL, no printing occurs.
*
* If -DNPRINT is defined at compile-time, stdio.h is not included. Printing
* can then be enabled at run-time by setting amd_printf to a non-NULL function.
*/
#ifndef NPRINT
#ifdef MATLAB_MEX_FILE
int (*amd_printf) (const char *, ...) = mexPrintf ;
#else
#include <stdio.h>
int (*amd_printf) (const char *, ...) = printf ;
#endif
#else
int (*amd_printf) (const char *, ...) = NULL ;
#endif

120
src/maths/KLU/amd_info.c Normal file
View File

@ -0,0 +1,120 @@
/* ========================================================================= */
/* === AMD_info ============================================================ */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* User-callable. Prints the output statistics for AMD. See amd.h
* for details. If the Info array is not present, nothing is printed.
*/
#include "amd_internal.h"
#define PRI(format,x) { if (x >= 0) { PRINTF ((format, x)) ; }}
GLOBAL void AMD_info
(
double Info [ ]
)
{
double n, ndiv, nmultsubs_ldl, nmultsubs_lu, lnz, lnzd ;
PRINTF (("\nAMD version %d.%d.%d, %s, results:\n",
AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE)) ;
if (!Info)
{
return ;
}
n = Info [AMD_N] ;
ndiv = Info [AMD_NDIV] ;
nmultsubs_ldl = Info [AMD_NMULTSUBS_LDL] ;
nmultsubs_lu = Info [AMD_NMULTSUBS_LU] ;
lnz = Info [AMD_LNZ] ;
lnzd = (n >= 0 && lnz >= 0) ? (n + lnz) : (-1) ;
/* AMD return status */
PRINTF ((" status: ")) ;
if (Info [AMD_STATUS] == AMD_OK)
{
PRINTF (("OK\n")) ;
}
else if (Info [AMD_STATUS] == AMD_OUT_OF_MEMORY)
{
PRINTF (("out of memory\n")) ;
}
else if (Info [AMD_STATUS] == AMD_INVALID)
{
PRINTF (("invalid matrix\n")) ;
}
else if (Info [AMD_STATUS] == AMD_OK_BUT_JUMBLED)
{
PRINTF (("OK, but jumbled\n")) ;
}
else
{
PRINTF (("unknown\n")) ;
}
/* statistics about the input matrix */
PRI (" n, dimension of A: %.20g\n", n);
PRI (" nz, number of nonzeros in A: %.20g\n",
Info [AMD_NZ]) ;
PRI (" symmetry of A: %.4f\n",
Info [AMD_SYMMETRY]) ;
PRI (" number of nonzeros on diagonal: %.20g\n",
Info [AMD_NZDIAG]) ;
PRI (" nonzeros in pattern of A+A' (excl. diagonal): %.20g\n",
Info [AMD_NZ_A_PLUS_AT]) ;
PRI (" # dense rows/columns of A+A': %.20g\n",
Info [AMD_NDENSE]) ;
/* statistics about AMD's behavior */
PRI (" memory used, in bytes: %.20g\n",
Info [AMD_MEMORY]) ;
PRI (" # of memory compactions: %.20g\n",
Info [AMD_NCMPA]) ;
/* statistics about the ordering quality */
PRINTF (("\n"
" The following approximate statistics are for a subsequent\n"
" factorization of A(P,P) + A(P,P)'. They are slight upper\n"
" bounds if there are no dense rows/columns in A+A', and become\n"
" looser if dense rows/columns exist.\n\n")) ;
PRI (" nonzeros in L (excluding diagonal): %.20g\n",
lnz) ;
PRI (" nonzeros in L (including diagonal): %.20g\n",
lnzd) ;
PRI (" # divide operations for LDL' or LU: %.20g\n",
ndiv) ;
PRI (" # multiply-subtract operations for LDL': %.20g\n",
nmultsubs_ldl) ;
PRI (" # multiply-subtract operations for LU: %.20g\n",
nmultsubs_lu) ;
PRI (" max nz. in any column of L (incl. diagonal): %.20g\n",
Info [AMD_DMAX]) ;
/* total flop counts for various factorizations */
if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0)
{
PRINTF (("\n"
" chol flop count for real A, sqrt counted as 1 flop: %.20g\n"
" LDL' flop count for real A: %.20g\n"
" LDL' flop count for complex A: %.20g\n"
" LU flop count for real A (with no pivoting): %.20g\n"
" LU flop count for complex A (with no pivoting): %.20g\n\n",
n + ndiv + 2*nmultsubs_ldl,
ndiv + 2*nmultsubs_ldl,
9*ndiv + 8*nmultsubs_ldl,
ndiv + 2*nmultsubs_lu,
9*ndiv + 8*nmultsubs_lu)) ;
}
}

View File

@ -0,0 +1,350 @@
/* ========================================================================= */
/* === amd_internal.h ====================================================== */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* This file is for internal use in AMD itself, and does not normally need to
* be included in user code (it is included in UMFPACK, however). All others
* should use amd.h instead.
*
* The following compile-time definitions affect how AMD is compiled.
*
* -DNPRINT
*
* Disable all printing. stdio.h will not be included. Printing can
* be re-enabled at run-time by setting the global pointer amd_printf
* to printf (or mexPrintf for a MATLAB mexFunction).
*
* -DNMALLOC
*
* No memory manager is defined at compile-time. You MUST define the
* function pointers amd_malloc, amd_free, amd_realloc, and
* amd_calloc at run-time for AMD to work properly.
*/
/* ========================================================================= */
/* === NDEBUG ============================================================== */
/* ========================================================================= */
/*
* Turning on debugging takes some work (see below). If you do not edit this
* file, then debugging is always turned off, regardless of whether or not
* -DNDEBUG is specified in your compiler options.
*
* If AMD is being compiled as a mexFunction, then MATLAB_MEX_FILE is defined,
* and mxAssert is used instead of assert. If debugging is not enabled, no
* MATLAB include files or functions are used. Thus, the AMD library libamd.a
* can be safely used in either a stand-alone C program or in another
* mexFunction, without any change.
*/
/*
AMD will be exceedingly slow when running in debug mode. The next three
lines ensure that debugging is turned off.
*/
#ifndef NDEBUG
#define NDEBUG
#endif
/*
To enable debugging, uncomment the following line:
#undef NDEBUG
*/
/* ------------------------------------------------------------------------- */
/* ANSI include files */
/* ------------------------------------------------------------------------- */
/* from stdlib.h: size_t, malloc, free, realloc, and calloc */
#include <stdlib.h>
#if !defined(NPRINT) || !defined(NDEBUG)
/* from stdio.h: printf. Not included if NPRINT is defined at compile time.
* fopen and fscanf are used when debugging. */
#include <stdio.h>
#endif
/* from limits.h: INT_MAX and LONG_MAX */
#include <limits.h>
/* from math.h: sqrt */
#include <math.h>
/* ------------------------------------------------------------------------- */
/* MATLAB include files (only if being used in or via MATLAB) */
/* ------------------------------------------------------------------------- */
#ifdef MATLAB_MEX_FILE
#include "matrix.h"
#include "mex.h"
#endif
/* ------------------------------------------------------------------------- */
/* basic definitions */
/* ------------------------------------------------------------------------- */
#ifdef FLIP
#undef FLIP
#endif
#ifdef MAX
#undef MAX
#endif
#ifdef MIN
#undef MIN
#endif
#ifdef EMPTY
#undef EMPTY
#endif
#ifdef GLOBAL
#undef GLOBAL
#endif
#ifdef PRIVATE
#undef PRIVATE
#endif
/* FLIP is a "negation about -1", and is used to mark an integer i that is
* normally non-negative. FLIP (EMPTY) is EMPTY. FLIP of a number > EMPTY
* is negative, and FLIP of a number < EMTPY is positive. FLIP (FLIP (i)) = i
* for all integers i. UNFLIP (i) is >= EMPTY. */
#define EMPTY (-1)
#define FLIP(i) (-(i)-2)
#define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i))
/* for integer MAX/MIN, or for doubles when we don't care how NaN's behave: */
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
/* logical expression of p implies q: */
#define IMPLIES(p,q) (!(p) || (q))
/* Note that the IBM RS 6000 xlc predefines TRUE and FALSE in <types.h>. */
/* The Compaq Alpha also predefines TRUE and FALSE. */
#ifdef TRUE
#undef TRUE
#endif
#ifdef FALSE
#undef FALSE
#endif
#define TRUE (1)
#define FALSE (0)
#define PRIVATE static
#define GLOBAL
#define EMPTY (-1)
/* Note that Linux's gcc 2.96 defines NULL as ((void *) 0), but other */
/* compilers (even gcc 2.95.2 on Solaris) define NULL as 0 or (0). We */
/* need to use the ANSI standard value of 0. */
#ifdef NULL
#undef NULL
#endif
#define NULL 0
/* largest value of size_t */
#ifndef SIZE_T_MAX
#define SIZE_T_MAX ((size_t) (-1))
#endif
/* ------------------------------------------------------------------------- */
/* integer type for AMD: int or UF_long */
/* ------------------------------------------------------------------------- */
/* define UF_long */
#include "ngspice/UFconfig.h"
#if defined (DLONG) || defined (ZLONG)
#define Int UF_long
#define ID UF_long_id
#define Int_MAX UF_long_max
#define AMD_order amd_l_order
#define AMD_defaults amd_l_defaults
#define AMD_control amd_l_control
#define AMD_info amd_l_info
#define AMD_1 amd_l1
#define AMD_2 amd_l2
#define AMD_valid amd_l_valid
#define AMD_aat amd_l_aat
#define AMD_postorder amd_l_postorder
#define AMD_post_tree amd_l_post_tree
#define AMD_dump amd_l_dump
#define AMD_debug amd_l_debug
#define AMD_debug_init amd_l_debug_init
#define AMD_preprocess amd_l_preprocess
#else
#define Int int
#define ID "%d"
#define Int_MAX INT_MAX
#define AMD_order amd_order
#define AMD_defaults amd_defaults
#define AMD_control amd_control
#define AMD_info amd_info
#define AMD_1 amd_1
#define AMD_2 amd_2
#define AMD_valid amd_valid
#define AMD_aat amd_aat
#define AMD_postorder amd_postorder
#define AMD_post_tree amd_post_tree
#define AMD_dump amd_dump
#define AMD_debug amd_debug
#define AMD_debug_init amd_debug_init
#define AMD_preprocess amd_preprocess
#endif
/* ========================================================================= */
/* === PRINTF macro ======================================================== */
/* ========================================================================= */
/* All output goes through the PRINTF macro. */
#define PRINTF(params) { if (amd_printf != NULL) (void) amd_printf params ; }
/* ------------------------------------------------------------------------- */
/* AMD routine definitions (user-callable) */
/* ------------------------------------------------------------------------- */
#include "ngspice/amd.h"
/* ------------------------------------------------------------------------- */
/* AMD routine definitions (not user-callable) */
/* ------------------------------------------------------------------------- */
GLOBAL size_t AMD_aat
(
Int n,
const Int Ap [ ],
const Int Ai [ ],
Int Len [ ],
Int Tp [ ],
double Info [ ]
) ;
GLOBAL void AMD_1
(
Int n,
const Int Ap [ ],
const Int Ai [ ],
Int P [ ],
Int Pinv [ ],
Int Len [ ],
Int slen,
Int S [ ],
double Control [ ],
double Info [ ]
) ;
GLOBAL void AMD_postorder
(
Int nn,
Int Parent [ ],
Int Npiv [ ],
Int Fsize [ ],
Int Order [ ],
Int Child [ ],
Int Sibling [ ],
Int Stack [ ]
) ;
GLOBAL Int AMD_post_tree
(
Int root,
Int k,
Int Child [ ],
const Int Sibling [ ],
Int Order [ ],
Int Stack [ ]
#ifndef NDEBUG
, Int nn
#endif
) ;
GLOBAL void AMD_preprocess
(
Int n,
const Int Ap [ ],
const Int Ai [ ],
Int Rp [ ],
Int Ri [ ],
Int W [ ],
Int Flag [ ]
) ;
/* ------------------------------------------------------------------------- */
/* debugging definitions */
/* ------------------------------------------------------------------------- */
#ifndef NDEBUG
/* from assert.h: assert macro */
#include <assert.h>
#ifndef EXTERN
#define EXTERN extern
#endif
EXTERN Int AMD_debug ;
GLOBAL void AMD_debug_init ( char *s ) ;
GLOBAL void AMD_dump
(
Int n,
Int Pe [ ],
Int Iw [ ],
Int Len [ ],
Int iwlen,
Int pfree,
Int Nv [ ],
Int Next [ ],
Int Last [ ],
Int Head [ ],
Int Elen [ ],
Int Degree [ ],
Int W [ ],
Int nel
) ;
#ifdef ASSERT
#undef ASSERT
#endif
/* Use mxAssert if AMD is compiled into a mexFunction */
#ifdef MATLAB_MEX_FILE
#define ASSERT(expression) (mxAssert ((expression), ""))
#else
#define ASSERT(expression) (assert (expression))
#endif
#define AMD_DEBUG0(params) { PRINTF (params) ; }
#define AMD_DEBUG1(params) { if (AMD_debug >= 1) PRINTF (params) ; }
#define AMD_DEBUG2(params) { if (AMD_debug >= 2) PRINTF (params) ; }
#define AMD_DEBUG3(params) { if (AMD_debug >= 3) PRINTF (params) ; }
#define AMD_DEBUG4(params) { if (AMD_debug >= 4) PRINTF (params) ; }
#else
/* no debugging */
#define ASSERT(expression)
#define AMD_DEBUG0(params)
#define AMD_DEBUG1(params)
#define AMD_DEBUG2(params)
#define AMD_DEBUG3(params)
#define AMD_DEBUG4(params)
#endif

200
src/maths/KLU/amd_order.c Normal file
View File

@ -0,0 +1,200 @@
/* ========================================================================= */
/* === AMD_order =========================================================== */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* User-callable AMD minimum degree ordering routine. See amd.h for
* documentation.
*/
#include "amd_internal.h"
/* ========================================================================= */
/* === AMD_order =========================================================== */
/* ========================================================================= */
GLOBAL Int AMD_order
(
Int n,
const Int Ap [ ],
const Int Ai [ ],
Int P [ ],
double Control [ ],
double Info [ ]
)
{
Int *Len, *S, nz, i, *Pinv, info, status, *Rp, *Ri, *Cp, *Ci, ok ;
size_t nzaat, slen ;
double mem = 0 ;
#ifndef NDEBUG
AMD_debug_init ("amd") ;
#endif
/* clear the Info array, if it exists */
info = Info != (double *) NULL ;
if (info)
{
for (i = 0 ; i < AMD_INFO ; i++)
{
Info [i] = EMPTY ;
}
Info [AMD_N] = n ;
Info [AMD_STATUS] = AMD_OK ;
}
/* make sure inputs exist and n is >= 0 */
if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0)
{
if (info) Info [AMD_STATUS] = AMD_INVALID ;
return (AMD_INVALID) ; /* arguments are invalid */
}
if (n == 0)
{
return (AMD_OK) ; /* n is 0 so there's nothing to do */
}
nz = Ap [n] ;
if (info)
{
Info [AMD_NZ] = nz ;
}
if (nz < 0)
{
if (info) Info [AMD_STATUS] = AMD_INVALID ;
return (AMD_INVALID) ;
}
/* check if n or nz will cause size_t overflow */
if (((size_t) n) >= SIZE_T_MAX / sizeof (Int)
|| ((size_t) nz) >= SIZE_T_MAX / sizeof (Int))
{
if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
return (AMD_OUT_OF_MEMORY) ; /* problem too large */
}
/* check the input matrix: AMD_OK, AMD_INVALID, or AMD_OK_BUT_JUMBLED */
status = AMD_valid (n, n, Ap, Ai) ;
if (status == AMD_INVALID)
{
if (info) Info [AMD_STATUS] = AMD_INVALID ;
return (AMD_INVALID) ; /* matrix is invalid */
}
/* allocate two size-n integer workspaces */
Len = amd_malloc (n * sizeof (Int)) ;
Pinv = amd_malloc (n * sizeof (Int)) ;
mem += n ;
mem += n ;
if (!Len || !Pinv)
{
/* :: out of memory :: */
amd_free (Len) ;
amd_free (Pinv) ;
if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
return (AMD_OUT_OF_MEMORY) ;
}
if (status == AMD_OK_BUT_JUMBLED)
{
/* sort the input matrix and remove duplicate entries */
AMD_DEBUG1 (("Matrix is jumbled\n")) ;
Rp = amd_malloc ((n+1) * sizeof (Int)) ;
Ri = amd_malloc (MAX (nz,1) * sizeof (Int)) ;
mem += (n+1) ;
mem += MAX (nz,1) ;
if (!Rp || !Ri)
{
/* :: out of memory :: */
amd_free (Rp) ;
amd_free (Ri) ;
amd_free (Len) ;
amd_free (Pinv) ;
if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
return (AMD_OUT_OF_MEMORY) ;
}
/* use Len and Pinv as workspace to create R = A' */
AMD_preprocess (n, Ap, Ai, Rp, Ri, Len, Pinv) ;
Cp = Rp ;
Ci = Ri ;
}
else
{
/* order the input matrix as-is. No need to compute R = A' first */
Rp = NULL ;
Ri = NULL ;
Cp = (Int *) Ap ;
Ci = (Int *) Ai ;
}
/* --------------------------------------------------------------------- */
/* determine the symmetry and count off-diagonal nonzeros in A+A' */
/* --------------------------------------------------------------------- */
nzaat = AMD_aat (n, Cp, Ci, Len, P, Info) ;
AMD_DEBUG1 (("nzaat: %g\n", (double) nzaat)) ;
ASSERT ((MAX (nz-n, 0) <= nzaat) && (nzaat <= 2 * (size_t) nz)) ;
/* --------------------------------------------------------------------- */
/* allocate workspace for matrix, elbow room, and 6 size-n vectors */
/* --------------------------------------------------------------------- */
S = NULL ;
slen = nzaat ; /* space for matrix */
ok = ((slen + nzaat/5) >= slen) ; /* check for size_t overflow */
slen += nzaat/5 ; /* add elbow room */
for (i = 0 ; ok && i < 7 ; i++)
{
ok = ((slen + n) > slen) ; /* check for size_t overflow */
slen += n ; /* size-n elbow room, 6 size-n work */
}
mem += slen ;
ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */
ok = ok && (slen < Int_MAX) ; /* S[i] for Int i must be OK */
if (ok)
{
S = amd_malloc (slen * sizeof (Int)) ;
}
AMD_DEBUG1 (("slen %g\n", (double) slen)) ;
if (!S)
{
/* :: out of memory :: (or problem too large) */
amd_free (Rp) ;
amd_free (Ri) ;
amd_free (Len) ;
amd_free (Pinv) ;
if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
return (AMD_OUT_OF_MEMORY) ;
}
if (info)
{
/* memory usage, in bytes. */
Info [AMD_MEMORY] = mem * sizeof (Int) ;
}
/* --------------------------------------------------------------------- */
/* order the matrix */
/* --------------------------------------------------------------------- */
AMD_1 (n, Cp, Ci, P, Pinv, Len, slen, S, Control, Info) ;
/* --------------------------------------------------------------------- */
/* free the workspace */
/* --------------------------------------------------------------------- */
amd_free (Rp) ;
amd_free (Ri) ;
amd_free (Len) ;
amd_free (Pinv) ;
amd_free (S) ;
if (info) Info [AMD_STATUS] = status ;
return (status) ; /* successful ordering */
}

View File

@ -0,0 +1,121 @@
/* ========================================================================= */
/* === AMD_post_tree ======================================================= */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* Post-ordering of a supernodal elimination tree. */
#include "amd_internal.h"
GLOBAL Int AMD_post_tree
(
Int root, /* root of the tree */
Int k, /* start numbering at k */
Int Child [ ], /* input argument of size nn, undefined on
* output. Child [i] is the head of a link
* list of all nodes that are children of node
* i in the tree. */
const Int Sibling [ ], /* input argument of size nn, not modified.
* If f is a node in the link list of the
* children of node i, then Sibling [f] is the
* next child of node i.
*/
Int Order [ ], /* output order, of size nn. Order [i] = k
* if node i is the kth node of the reordered
* tree. */
Int Stack [ ] /* workspace of size nn */
#ifndef NDEBUG
, Int nn /* nodes are in the range 0..nn-1. */
#endif
)
{
Int f, head, h, i ;
#if 0
/* --------------------------------------------------------------------- */
/* recursive version (Stack [ ] is not used): */
/* --------------------------------------------------------------------- */
/* this is simple, but can caouse stack overflow if nn is large */
i = root ;
for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
{
k = AMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ;
}
Order [i] = k++ ;
return (k) ;
#endif
/* --------------------------------------------------------------------- */
/* non-recursive version, using an explicit stack */
/* --------------------------------------------------------------------- */
/* push root on the stack */
head = 0 ;
Stack [0] = root ;
while (head >= 0)
{
/* get head of stack */
ASSERT (head < nn) ;
i = Stack [head] ;
AMD_DEBUG1 (("head of stack "ID" \n", i)) ;
ASSERT (i >= 0 && i < nn) ;
if (Child [i] != EMPTY)
{
/* the children of i are not yet ordered */
/* push each child onto the stack in reverse order */
/* so that small ones at the head of the list get popped first */
/* and the biggest one at the end of the list gets popped last */
for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
{
head++ ;
ASSERT (head < nn) ;
ASSERT (f >= 0 && f < nn) ;
}
h = head ;
ASSERT (head < nn) ;
for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
{
ASSERT (h > 0) ;
Stack [h--] = f ;
AMD_DEBUG1 (("push "ID" on stack\n", f)) ;
ASSERT (f >= 0 && f < nn) ;
}
ASSERT (Stack [h] == i) ;
/* delete child list so that i gets ordered next time we see it */
Child [i] = EMPTY ;
}
else
{
/* the children of i (if there were any) are already ordered */
/* remove i from the stack and order it. Front i is kth front */
head-- ;
AMD_DEBUG1 (("pop "ID" order "ID"\n", i, k)) ;
Order [i] = k++ ;
ASSERT (k <= nn) ;
}
#ifndef NDEBUG
AMD_DEBUG1 (("\nStack:")) ;
for (h = head ; h >= 0 ; h--)
{
Int j = Stack [h] ;
AMD_DEBUG1 ((" "ID, j)) ;
ASSERT (j >= 0 && j < nn) ;
}
AMD_DEBUG1 (("\n\n")) ;
ASSERT (head < nn) ;
#endif
}
return (k) ;
}

View File

@ -0,0 +1,207 @@
/* ========================================================================= */
/* === AMD_postorder ======================================================= */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* Perform a postordering (via depth-first search) of an assembly tree. */
#include "amd_internal.h"
GLOBAL void AMD_postorder
(
/* inputs, not modified on output: */
Int nn, /* nodes are in the range 0..nn-1 */
Int Parent [ ], /* Parent [j] is the parent of j, or EMPTY if root */
Int Nv [ ], /* Nv [j] > 0 number of pivots represented by node j,
* or zero if j is not a node. */
Int Fsize [ ], /* Fsize [j]: size of node j */
/* output, not defined on input: */
Int Order [ ], /* output post-order */
/* workspaces of size nn: */
Int Child [ ],
Int Sibling [ ],
Int Stack [ ]
)
{
Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ;
for (j = 0 ; j < nn ; j++)
{
Child [j] = EMPTY ;
Sibling [j] = EMPTY ;
}
/* --------------------------------------------------------------------- */
/* place the children in link lists - bigger elements tend to be last */
/* --------------------------------------------------------------------- */
for (j = nn-1 ; j >= 0 ; j--)
{
if (Nv [j] > 0)
{
/* this is an element */
parent = Parent [j] ;
if (parent != EMPTY)
{
/* place the element in link list of the children its parent */
/* bigger elements will tend to be at the end of the list */
Sibling [j] = Child [parent] ;
Child [parent] = j ;
}
}
}
#ifndef NDEBUG
{
Int nels, ff, nchild ;
AMD_DEBUG1 (("\n\n================================ AMD_postorder:\n"));
nels = 0 ;
for (j = 0 ; j < nn ; j++)
{
if (Nv [j] > 0)
{
AMD_DEBUG1 (( ""ID" : nels "ID" npiv "ID" size "ID
" parent "ID" maxfr "ID"\n", j, nels,
Nv [j], Fsize [j], Parent [j], Fsize [j])) ;
/* this is an element */
/* dump the link list of children */
nchild = 0 ;
AMD_DEBUG1 ((" Children: ")) ;
for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff])
{
AMD_DEBUG1 ((ID" ", ff)) ;
ASSERT (Parent [ff] == j) ;
nchild++ ;
ASSERT (nchild < nn) ;
}
AMD_DEBUG1 (("\n")) ;
parent = Parent [j] ;
if (parent != EMPTY)
{
ASSERT (Nv [parent] > 0) ;
}
nels++ ;
}
}
}
AMD_DEBUG1 (("\n\nGo through the children of each node, and put\n"
"the biggest child last in each list:\n")) ;
#endif
/* --------------------------------------------------------------------- */
/* place the largest child last in the list of children for each node */
/* --------------------------------------------------------------------- */
for (i = 0 ; i < nn ; i++)
{
if (Nv [i] > 0 && Child [i] != EMPTY)
{
#ifndef NDEBUG
Int nchild ;
AMD_DEBUG1 (("Before partial sort, element "ID"\n", i)) ;
nchild = 0 ;
for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
{
ASSERT (f >= 0 && f < nn) ;
AMD_DEBUG1 ((" f: "ID" size: "ID"\n", f, Fsize [f])) ;
nchild++ ;
ASSERT (nchild <= nn) ;
}
#endif
/* find the biggest element in the child list */
fprev = EMPTY ;
maxfrsize = EMPTY ;
bigfprev = EMPTY ;
bigf = EMPTY ;
for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
{
ASSERT (f >= 0 && f < nn) ;
frsize = Fsize [f] ;
if (frsize >= maxfrsize)
{
/* this is the biggest seen so far */
maxfrsize = frsize ;
bigfprev = fprev ;
bigf = f ;
}
fprev = f ;
}
ASSERT (bigf != EMPTY) ;
fnext = Sibling [bigf] ;
AMD_DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID
" fprev " ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ;
if (fnext != EMPTY)
{
/* if fnext is EMPTY then bigf is already at the end of list */
if (bigfprev == EMPTY)
{
/* delete bigf from the element of the list */
Child [i] = fnext ;
}
else
{
/* delete bigf from the middle of the list */
Sibling [bigfprev] = fnext ;
}
/* put bigf at the end of the list */
Sibling [bigf] = EMPTY ;
ASSERT (Child [i] != EMPTY) ;
ASSERT (fprev != bigf) ;
ASSERT (fprev != EMPTY) ;
Sibling [fprev] = bigf ;
}
#ifndef NDEBUG
AMD_DEBUG1 (("After partial sort, element "ID"\n", i)) ;
for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
{
ASSERT (f >= 0 && f < nn) ;
AMD_DEBUG1 ((" "ID" "ID"\n", f, Fsize [f])) ;
ASSERT (Nv [f] > 0) ;
nchild-- ;
}
ASSERT (nchild == 0) ;
#endif
}
}
/* --------------------------------------------------------------------- */
/* postorder the assembly tree */
/* --------------------------------------------------------------------- */
for (i = 0 ; i < nn ; i++)
{
Order [i] = EMPTY ;
}
k = 0 ;
for (i = 0 ; i < nn ; i++)
{
if (Parent [i] == EMPTY && Nv [i] > 0)
{
AMD_DEBUG1 (("Root of assembly tree "ID"\n", i)) ;
k = AMD_post_tree (i, k, Child, Sibling, Order, Stack
#ifndef NDEBUG
, nn
#endif
) ;
}
}
}

View File

@ -0,0 +1,119 @@
/* ========================================================================= */
/* === AMD_preprocess ====================================================== */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* Sorts, removes duplicate entries, and transposes from the nonzero pattern of
* a column-form matrix A, to obtain the matrix R. The input matrix can have
* duplicate entries and/or unsorted columns (AMD_valid (n,Ap,Ai) must not be
* AMD_INVALID).
*
* This input condition is NOT checked. This routine is not user-callable.
*/
#include "amd_internal.h"
/* ========================================================================= */
/* === AMD_preprocess ====================================================== */
/* ========================================================================= */
/* AMD_preprocess does not check its input for errors or allocate workspace.
* On input, the condition (AMD_valid (n,n,Ap,Ai) != AMD_INVALID) must hold.
*/
GLOBAL void AMD_preprocess
(
Int n, /* input matrix: A is n-by-n */
const Int Ap [ ], /* size n+1 */
const Int Ai [ ], /* size nz = Ap [n] */
/* output matrix R: */
Int Rp [ ], /* size n+1 */
Int Ri [ ], /* size nz (or less, if duplicates present) */
Int W [ ], /* workspace of size n */
Int Flag [ ] /* workspace of size n */
)
{
/* --------------------------------------------------------------------- */
/* local variables */
/* --------------------------------------------------------------------- */
Int i, j, p, p2 ;
ASSERT (AMD_valid (n, n, Ap, Ai) != AMD_INVALID) ;
/* --------------------------------------------------------------------- */
/* count the entries in each row of A (excluding duplicates) */
/* --------------------------------------------------------------------- */
for (i = 0 ; i < n ; i++)
{
W [i] = 0 ; /* # of nonzeros in row i (excl duplicates) */
Flag [i] = EMPTY ; /* Flag [i] = j if i appears in column j */
}
for (j = 0 ; j < n ; j++)
{
p2 = Ap [j+1] ;
for (p = Ap [j] ; p < p2 ; p++)
{
i = Ai [p] ;
if (Flag [i] != j)
{
/* row index i has not yet appeared in column j */
W [i]++ ; /* one more entry in row i */
Flag [i] = j ; /* flag row index i as appearing in col j*/
}
}
}
/* --------------------------------------------------------------------- */
/* compute the row pointers for R */
/* --------------------------------------------------------------------- */
Rp [0] = 0 ;
for (i = 0 ; i < n ; i++)
{
Rp [i+1] = Rp [i] + W [i] ;
}
for (i = 0 ; i < n ; i++)
{
W [i] = Rp [i] ;
Flag [i] = EMPTY ;
}
/* --------------------------------------------------------------------- */
/* construct the row form matrix R */
/* --------------------------------------------------------------------- */
/* R = row form of pattern of A */
for (j = 0 ; j < n ; j++)
{
p2 = Ap [j+1] ;
for (p = Ap [j] ; p < p2 ; p++)
{
i = Ai [p] ;
if (Flag [i] != j)
{
/* row index i has not yet appeared in column j */
Ri [W [i]++] = j ; /* put col j in row i */
Flag [i] = j ; /* flag row index i as appearing in col j*/
}
}
}
#ifndef NDEBUG
ASSERT (AMD_valid (n, n, Rp, Ri) == AMD_OK) ;
for (j = 0 ; j < n ; j++)
{
ASSERT (W [j] == Rp [j+1]) ;
}
#endif
}

93
src/maths/KLU/amd_valid.c Normal file
View File

@ -0,0 +1,93 @@
/* ========================================================================= */
/* === AMD_valid =========================================================== */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* AMD, Copyright (c) Timothy A. Davis, */
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
/* web: http://www.cise.ufl.edu/research/sparse/amd */
/* ------------------------------------------------------------------------- */
/* Check if a column-form matrix is valid or not. The matrix A is
* n_row-by-n_col. The row indices of entries in column j are in
* Ai [Ap [j] ... Ap [j+1]-1]. Required conditions are:
*
* n_row >= 0
* n_col >= 0
* nz = Ap [n_col] >= 0 number of entries in the matrix
* Ap [0] == 0
* Ap [j] <= Ap [j+1] for all j in the range 0 to n_col.
* Ai [0 ... nz-1] must be in the range 0 to n_row-1.
*
* If any of the above conditions hold, AMD_INVALID is returned. If the
* following condition holds, AMD_OK_BUT_JUMBLED is returned (a warning,
* not an error):
*
* row indices in Ai [Ap [j] ... Ap [j+1]-1] are not sorted in ascending
* order, and/or duplicate entries exist.
*
* Otherwise, AMD_OK is returned.
*
* In v1.2 and earlier, this function returned TRUE if the matrix was valid
* (now returns AMD_OK), or FALSE otherwise (now returns AMD_INVALID or
* AMD_OK_BUT_JUMBLED).
*/
#include "amd_internal.h"
GLOBAL Int AMD_valid
(
/* inputs, not modified on output: */
Int n_row, /* A is n_row-by-n_col */
Int n_col,
const Int Ap [ ], /* column pointers of A, of size n_col+1 */
const Int Ai [ ] /* row indices of A, of size nz = Ap [n_col] */
)
{
Int nz, j, p1, p2, ilast, i, p, result = AMD_OK ;
if (n_row < 0 || n_col < 0 || Ap == NULL || Ai == NULL)
{
return (AMD_INVALID) ;
}
nz = Ap [n_col] ;
if (Ap [0] != 0 || nz < 0)
{
/* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */
AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ;
return (AMD_INVALID) ;
}
for (j = 0 ; j < n_col ; j++)
{
p1 = Ap [j] ;
p2 = Ap [j+1] ;
AMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ;
if (p1 > p2)
{
/* column pointers must be ascending */
AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ;
return (AMD_INVALID) ;
}
ilast = EMPTY ;
for (p = p1 ; p < p2 ; p++)
{
i = Ai [p] ;
AMD_DEBUG3 (("row: "ID"\n", i)) ;
if (i < 0 || i >= n_row)
{
/* row index out of range */
AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i));
return (AMD_INVALID) ;
}
if (i <= ilast)
{
/* row index unsorted, or duplicate entry present */
AMD_DEBUG1 (("index unsorted/dupl col "ID" row "ID"\n", j, i));
result = AMD_OK_BUT_JUMBLED ;
}
ilast = i ;
}
}
return (result) ;
}

View File

@ -0,0 +1,64 @@
/* ========================================================================== */
/* === btf_internal include file ============================================ */
/* ========================================================================== */
#ifndef _BTF_INTERNAL_H
#define _BTF_INTERNAL_H
/*
* Copyright (c) 2004-2007. Tim Davis, University of Florida,
* with support from Sandia National Laboratories. All Rights Reserved.
*/
/* Not to be included in any user program. */
#ifdef DLONG
#define Int UF_long
#define Int_id UF_long_id
#define BTF(name) btf_l_ ## name
#else
#define Int int
#define Int_id "%d"
#define BTF(name) btf_ ## name
#endif
/* ========================================================================== */
/* make sure debugging and printing is turned off */
#ifndef NDEBUG
#define NDEBUG
#endif
#ifndef NPRINT
#define NPRINT
#endif
/* To enable debugging and assertions, uncomment this line:
#undef NDEBUG
*/
/* To enable diagnostic printing, uncomment this line:
#undef NPRINT
*/
/* ========================================================================== */
#include <stdio.h>
#include <assert.h>
#define ASSERT(a) assert(a)
#undef TRUE
#undef FALSE
#undef PRINTF
#undef MIN
#ifndef NPRINT
#define PRINTF(s) { printf s ; } ;
#else
#define PRINTF(s)
#endif
#define TRUE 1
#define FALSE 0
#define EMPTY (-1)
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif

View File

@ -0,0 +1,387 @@
/* ========================================================================== */
/* === BTF_MAXTRANS ========================================================= */
/* ========================================================================== */
/* Finds a column permutation that maximizes the number of entries on the
* diagonal of a sparse matrix. See btf.h for more information.
*
* This function is identical to cs_maxtrans in CSparse, with the following
* exceptions:
*
* (1) cs_maxtrans finds both jmatch and imatch, where jmatch [i] = j and
* imatch [j] = i if row i is matched to column j. This function returns
* just jmatch (the Match array). The MATLAB interface to cs_maxtrans
* (the single-output cs_dmperm) returns imatch, not jmatch to the MATLAB
* caller.
*
* (2) cs_maxtrans includes a pre-pass that counts the number of non-empty
* rows and columns (m2 and n2, respectively), and computes the matching
* using the transpose of A if m2 < n2. cs_maxtrans also returns quickly
* if the diagonal of the matrix is already zero-free. This pre-pass
* allows cs_maxtrans to be much faster than maxtrans, if the use of the
* transpose is warranted.
*
* However, for square structurally non-singular matrices with one or more
* zeros on the diagonal, the pre-pass is a waste of time, and for these
* matrices, maxtrans can be twice as fast as cs_maxtrans. Since the
* maxtrans function is intended primarily for square matrices that are
* typically structurally nonsingular, the pre-pass is not included here.
* If this maxtrans function is used on a matrix with many more columns
* than rows, consider passing the transpose to this function, or use
* cs_maxtrans instead.
*
* (3) cs_maxtrans can operate as a randomized algorithm, to help avoid
* rare cases of excessive run-time.
*
* (4) this maxtrans function includes an option that limits the total work
* performed. If this limit is reached, the maximum transveral might not
* be found.
*
* Thus, for general usage, cs_maxtrans is preferred. For square matrices that
* are typically structurally non-singular, maxtrans is preferred. A partial
* maxtrans can still be very useful when solving a sparse linear system.
*
* Copyright (c) 2004-2007. Tim Davis, University of Florida,
* with support from Sandia National Laboratories. All Rights Reserved.
*/
#include "ngspice/btf.h"
#include "btf_internal.h"
/* ========================================================================== */
/* === augment ============================================================== */
/* ========================================================================== */
/* Perform a depth-first-search starting at column k, to find an augmenting
* path. An augmenting path is a sequence of row/column pairs (i1,k), (i2,j1),
* (i3,j2), ..., (i(s+1), js), such that all of the following properties hold:
*
* * column k is not matched to any row
* * entries in the path are nonzero
* * the pairs (i1,j1), (i2,j2), (i3,j3) ..., (is,js) have been
* previously matched to each other
* * (i(s+1), js) is nonzero, and row i(s+1) is not matched to any column
*
* Once this path is found, the matching can be changed to the set of pairs
* path. An augmenting path is a sequence of row/column pairs
*
* (i1,k), (i2,j1), (i3,j2), ..., (i(s+1), js)
*
* Once a row is matched with a column it remains matched with some column, but
* not necessarily the column it was first matched with.
*
* In the worst case, this function can examine every nonzero in A. Since it
* is called n times by maxtrans, the total time of maxtrans can be as high as
* O(n*nnz(A)). To limit this work, pass a value of maxwork > 0. Then at
* most O((maxwork+1)*nnz(A)) work will be performed; the maximum matching might
* not be found, however.
*
* This routine is very similar to the dfs routine in klu_kernel.c, in the
* KLU sparse LU factorization package. It is essentially identical to the
* cs_augment routine in CSparse, and its recursive version (augment function
* in cs_maxtransr_mex.c), except that this routine allows for the search to be
* terminated early if too much work is being performed.
*
* The algorithm is based on the paper "On Algorithms for obtaining a maximum
* transversal" by Iain Duff, ACM Trans. Mathematical Software, vol 7, no. 1,
* pp. 315-330, and "Algorithm 575: Permutations for a zero-free diagonal",
* same issue, pp. 387-390. The code here is a new implementation of that
* algorithm, with different data structures and control flow. After writing
* this code, I carefully compared my algorithm with MC21A/B (ACM Algorithm 575)
* Some of the comparisons are partial because I didn't dig deeply into all of
* the details of MC21A/B, such as how the stack is maintained. The following
* arguments are essentially identical between this code and MC21A:
*
* maxtrans MC21A,B
* -------- -------
* n N identical
* k JORD identical
* Ap IP column / row pointers
* Ai ICN row / column indices
* Ap[n] LICN length of index array (# of nonzeros in A)
* Match IPERM output column / row permutation
* nmatch NUMNZ # of nonzeros on diagonal of permuted matrix
* Flag CV mark a node as visited by the depth-first-search
*
* The following are different, but analogous:
*
* Cheap ARP indicates what part of the a column / row has
* already been matched.
*
* The following arguments are very different:
*
* - LENR # of entries in each row/column (unused in maxtrans)
* Pstack OUT Pstack keeps track of where we are in the depth-
* first-search scan of column j. I think that OUT
* plays a similar role in MC21B, but I'm unsure.
* Istack PR keeps track of the rows in the path. PR is a link
* list, though, whereas Istack is a stack. Maxtrans
* does not use any link lists.
* Jstack OUT? PR? the stack for nodes in the path (unsure)
*
* The following control structures are roughly comparable:
*
* maxtrans MC21B
* -------- -----
* for (k = 0 ; k < n ; k++) DO 100 JORD=1,N
* while (head >= 0) DO 70 K=1,JORD
* for (p = Cheap [j] ; ...) DO 20 II=IN1,IN2
* for (p = head ; ...) DO 90 K=1,JORD
*/
static Int augment
(
Int k, /* which stage of the main loop we're in */
Int Ap [ ], /* column pointers, size n+1 */
Int Ai [ ], /* row indices, size nz = Ap [n] */
Int Match [ ], /* size n, Match [i] = j if col j matched to i */
Int Cheap [ ], /* rows Ai [Ap [j] .. Cheap [j]-1] alread matched */
Int Flag [ ], /* Flag [j] = k if j already visited this stage */
Int Istack [ ], /* size n. Row index stack. */
Int Jstack [ ], /* size n. Column index stack. */
Int Pstack [ ], /* size n. Keeps track of position in adjacency list */
double *work, /* work performed by the depth-first-search */
double maxwork /* maximum work allowed */
)
{
/* local variables, but "global" to all DFS levels: */
Int found ; /* true if match found. */
Int head ; /* top of stack */
/* variables that are purely local to any one DFS level: */
Int j2 ; /* the next DFS goes to node j2 */
Int pend ; /* one past the end of the adjacency list for node j */
Int pstart ;
Int quick ;
/* variables that need to be pushed then popped from the stack: */
Int i ; /* the row tentatively matched to i if DFS successful */
Int j ; /* the DFS is at the current node j */
Int p ; /* current index into the adj. list for node j */
/* the variables i, j, and p are stacked in Istack, Jstack, and Pstack */
quick = (maxwork > 0) ;
/* start a DFS to find a match for column k */
found = FALSE ;
i = EMPTY ;
head = 0 ;
Jstack [0] = k ;
ASSERT (Flag [k] != k) ;
while (head >= 0)
{
j = Jstack [head] ;
pend = Ap [j+1] ;
if (Flag [j] != k) /* a node is not yet visited */
{
/* -------------------------------------------------------------- */
/* prework for node j */
/* -------------------------------------------------------------- */
/* first time that j has been visited */
Flag [j] = k ;
/* cheap assignment: find the next unmatched row in col j. This
* loop takes at most O(nnz(A)) time for the sum total of all
* calls to augment. */
for (p = Cheap [j] ; p < pend && !found ; p++)
{
i = Ai [p] ;
found = (Match [i] == EMPTY) ;
}
Cheap [j] = p ;
/* -------------------------------------------------------------- */
/* prepare for DFS */
if (found)
{
/* end of augmenting path, column j matched with row i */
Istack [head] = i ;
break ;
}
/* set Pstack [head] to the first entry in column j to scan */
Pstack [head] = Ap [j] ;
}
/* ------------------------------------------------------------------ */
/* quick return if too much work done */
/* ------------------------------------------------------------------ */
if (quick && *work > maxwork)
{
/* too much work has been performed; abort the search */
return (EMPTY) ;
}
/* ------------------------------------------------------------------ */
/* DFS for nodes adjacent to j */
/* ------------------------------------------------------------------ */
/* If cheap assignment not made, continue the depth-first search. All
* rows in column j are already matched. Add the adjacent nodes to the
* stack by iterating through until finding another non-visited node.
*
* It is the following loop that can force maxtrans to take
* O(n*nnz(A)) time. */
pstart = Pstack [head] ;
for (p = pstart ; p < pend ; p++)
{
i = Ai [p] ;
j2 = Match [i] ;
ASSERT (j2 != EMPTY) ;
if (Flag [j2] != k)
{
/* Node j2 is not yet visited, start a depth-first search on
* node j2. Keep track of where we left off in the scan of adj
* list of node j so we can restart j where we left off. */
Pstack [head] = p + 1 ;
/* Push j2 onto the stack and immediately break so we can
* recurse on node j2. Also keep track of row i which (if this
* search for an augmenting path works) will be matched with the
* current node j. */
Istack [head] = i ;
Jstack [++head] = j2 ;
break ;
}
}
/* ------------------------------------------------------------------ */
/* determine how much work was just performed */
/* ------------------------------------------------------------------ */
*work += (p - pstart + 1) ;
/* ------------------------------------------------------------------ */
/* node j is done, but the postwork is postponed - see below */
/* ------------------------------------------------------------------ */
if (p == pend)
{
/* If all adjacent nodes of j are already visited, pop j from
* stack and continue. We failed to find a match. */
head-- ;
}
}
/* postwork for all nodes j in the stack */
/* unwind the path and make the corresponding matches */
if (found)
{
for (p = head ; p >= 0 ; p--)
{
j = Jstack [p] ;
i = Istack [p] ;
/* -------------------------------------------------------------- */
/* postwork for node j */
/* -------------------------------------------------------------- */
/* if found, match row i with column j */
Match [i] = j ;
}
}
return (found) ;
}
/* ========================================================================== */
/* === maxtrans ============================================================= */
/* ========================================================================== */
Int BTF(maxtrans) /* returns # of columns in the matching */
(
/* --- input --- */
Int nrow, /* A is nrow-by-ncol in compressed column form */
Int ncol,
Int Ap [ ], /* size ncol+1 */
Int Ai [ ], /* size nz = Ap [ncol] */
double maxwork, /* do at most maxwork*nnz(A) work; no limit if <= 0. This
* work limit excludes the O(nnz(A)) cheap-match phase. */
/* --- output --- */
double *work, /* work = -1 if maxwork > 0 and the total work performed
* reached the maximum of maxwork*nnz(A)).
* Otherwise, work = the total work performed. */
Int Match [ ], /* size nrow. Match [i] = j if column j matched to row i */
/* --- workspace --- */
Int Work [ ] /* size 5*ncol */
)
{
Int *Cheap, *Flag, *Istack, *Jstack, *Pstack ;
Int i, j, k, nmatch, work_limit_reached, result ;
/* ---------------------------------------------------------------------- */
/* get workspace and initialize */
/* ---------------------------------------------------------------------- */
Cheap = Work ; Work += ncol ;
Flag = Work ; Work += ncol ;
/* stack for non-recursive depth-first search in augment function */
Istack = Work ; Work += ncol ;
Jstack = Work ; Work += ncol ;
Pstack = Work ;
/* in column j, rows Ai [Ap [j] .. Cheap [j]-1] are known to be matched */
for (j = 0 ; j < ncol ; j++)
{
Cheap [j] = Ap [j] ;
Flag [j] = EMPTY ;
}
/* all rows and columns are currently unmatched */
for (i = 0 ; i < nrow ; i++)
{
Match [i] = EMPTY ;
}
if (maxwork > 0)
{
maxwork *= Ap [ncol] ;
}
*work = 0 ;
/* ---------------------------------------------------------------------- */
/* find a matching row for each column k */
/* ---------------------------------------------------------------------- */
nmatch = 0 ;
work_limit_reached = FALSE ;
for (k = 0 ; k < ncol ; k++)
{
/* find an augmenting path to match some row i to column k */
result = augment (k, Ap, Ai, Match, Cheap, Flag, Istack, Jstack, Pstack,
work, maxwork) ;
if (result == TRUE)
{
/* we found it. Match [i] = k for some row i has been done. */
nmatch++ ;
}
else if (result == EMPTY)
{
/* augment gave up because of too much work, and no match found */
work_limit_reached = TRUE ;
}
}
/* ---------------------------------------------------------------------- */
/* return the Match, and the # of matches made */
/* ---------------------------------------------------------------------- */
/* At this point, row i is matched to j = Match [i] if j >= 0. i is an
* unmatched row if Match [i] == EMPTY. */
if (work_limit_reached)
{
/* return -1 if the work limit of maxwork*nnz(A) was reached */
*work = EMPTY ;
}
return (nmatch) ;
}

132
src/maths/KLU/btf_order.c Normal file
View File

@ -0,0 +1,132 @@
/* ========================================================================== */
/* === BTF_ORDER ============================================================ */
/* ========================================================================== */
/* Find a permutation P and Q to permute a square sparse matrix into upper block
* triangular form. A(P,Q) will contain a zero-free diagonal if A has
* structural full-rank. Otherwise, the number of nonzeros on the diagonal of
* A(P,Q) will be maximized, and will equal the structural rank of A.
*
* Q[k] will be "flipped" if a zero-free diagonal was not found. Q[k] will be
* negative, and j = BTF_UNFLIP (Q [k]) gives the corresponding permutation.
*
* R defines the block boundaries of A(P,Q). The kth block consists of rows
* and columns R[k] to R[k+1]-1.
*
* If maxwork > 0 on input, then the work performed in btf_maxtrans is limited
* to maxwork*nnz(A) (excluding the "cheap match" phase, which can take another
* nnz(A) work). On output, the work parameter gives the actual work performed,
* or -1 if the limit was reached. In the latter case, the diagonal of A(P,Q)
* might not be zero-free, and the number of nonzeros on the diagonal of A(P,Q)
* might not be equal to the structural rank.
*
* See btf.h for more details.
*
* Copyright (c) 2004-2007. Tim Davis, University of Florida,
* with support from Sandia National Laboratories. All Rights Reserved.
*/
#include "ngspice/btf.h"
#include "btf_internal.h"
/* This function only operates on square matrices (either structurally full-
* rank, or structurally rank deficient). */
Int BTF(order) /* returns number of blocks found */
(
/* input, not modified: */
Int n, /* A is n-by-n in compressed column form */
Int Ap [ ], /* size n+1 */
Int Ai [ ], /* size nz = Ap [n] */
double maxwork, /* do at most maxwork*nnz(A) work in the maximum
* transversal; no limit if <= 0 */
/* output, not defined on input */
double *work, /* work performed in maxtrans, or -1 if limit reached */
Int P [ ], /* size n, row permutation */
Int Q [ ], /* size n, column permutation */
Int R [ ], /* size n+1. block b is in rows/cols R[b] ... R[b+1]-1 */
Int *nmatch, /* # nonzeros on diagonal of P*A*Q */
/* workspace, not defined on input or output */
Int Work [ ] /* size 5n */
)
{
Int *Flag ;
Int nblocks, i, j, nbadcol ;
/* ---------------------------------------------------------------------- */
/* compute the maximum matching */
/* ---------------------------------------------------------------------- */
/* if maxwork > 0, then a maximum matching might not be found */
*nmatch = BTF(maxtrans) (n, n, Ap, Ai, maxwork, work, Q, Work) ;
/* ---------------------------------------------------------------------- */
/* complete permutation if the matrix is structurally singular */
/* ---------------------------------------------------------------------- */
/* Since the matrix is square, ensure BTF_UNFLIP(Q[0..n-1]) is a
* permutation of the columns of A so that A has as many nonzeros on the
* diagonal as possible.
*/
if (*nmatch < n)
{
/* get a size-n work array */
Flag = Work + n ;
for (j = 0 ; j < n ; j++)
{
Flag [j] = 0 ;
}
/* flag all matched columns */
for (i = 0 ; i < n ; i++)
{
j = Q [i] ;
if (j != EMPTY)
{
/* row i and column j are matched to each other */
Flag [j] = 1 ;
}
}
/* make a list of all unmatched columns, in Work [0..nbadcol-1] */
nbadcol = 0 ;
for (j = n-1 ; j >= 0 ; j--)
{
if (!Flag [j])
{
/* j is matched to nobody */
Work [nbadcol++] = j ;
}
}
ASSERT (*nmatch + nbadcol == n) ;
/* make an assignment for each unmatched row */
for (i = 0 ; i < n ; i++)
{
if (Q [i] == EMPTY && nbadcol > 0)
{
/* get an unmatched column j */
j = Work [--nbadcol] ;
/* assign j to row i and flag the entry by "flipping" it */
Q [i] = BTF_FLIP (j) ;
}
}
}
/* The permutation of a square matrix can be recovered as follows: Row i is
* matched with column j, where j = BTF_UNFLIP (Q [i]) and where j
* will always be in the valid range 0 to n-1. The entry A(i,j) is zero
* if BTF_ISFLIPPED (Q [i]) is true, and nonzero otherwise. nmatch
* is the number of entries in the Q array that are non-negative. */
/* ---------------------------------------------------------------------- */
/* find the strongly connected components */
/* ---------------------------------------------------------------------- */
nblocks = BTF(strongcomp) (n, Ap, Ai, Q, P, R, Work) ;
return (nblocks) ;
}

View File

@ -0,0 +1,593 @@
/* ========================================================================== */
/* === BTF_STRONGCOMP ======================================================= */
/* ========================================================================== */
/* Finds the strongly connected components of a graph, or equivalently, permutes
* the matrix into upper block triangular form. See btf.h for more details.
* Input matrix and Q are not checked on input.
*
* Copyright (c) 2004-2007. Tim Davis, University of Florida,
* with support from Sandia National Laboratories. All Rights Reserved.
*/
#include "ngspice/btf.h"
#include "btf_internal.h"
#define UNVISITED (-2) /* Flag [j] = UNVISITED if node j not visited yet */
#define UNASSIGNED (-1) /* Flag [j] = UNASSIGNED if node j has been visited,
* but not yet assigned to a strongly-connected
* component (aka block). Flag [j] = k (k in the
* range 0 to nblocks-1) if node j has been visited
* (and completed, with its postwork done) and
* assigned to component k. */
/* This file contains two versions of the depth-first-search, a recursive one
* and a non-recursive one. By default, the non-recursive one is used. */
#ifndef RECURSIVE
/* ========================================================================== */
/* === dfs: non-recursive version (default) ================================= */
/* ========================================================================== */
/* Perform a depth-first-search of a graph, stored in an adjacency-list form.
* The row indices of column j (equivalently, the out-adjacency list of node j)
* are stored in Ai [Ap[j] ... Ap[j+1]-1]. Self-edge (diagonal entries) are
* ignored. Ap[0] must be zero, and thus nz = Ap[n] is the number of entries
* in the matrix (or edges in the graph). The row indices in each column need
* not be in any particular order. If an input column permutation is given,
* node j (in the permuted matrix A*Q) is located in
* Ai [Ap[Q[j]] ... Ap[Q[j]+1]-1]. This Q can be the same as the Match array
* output from the maxtrans routine, for a square matrix that is structurally
* full rank.
*
* The algorithm is from the paper by Robert E. Tarjan, "Depth-first search and
* linear graph algorithms," SIAM Journal on Computing, vol. 1, no. 2,
* pp. 146-160, 1972. The time taken by strongcomp is O(nnz(A)).
*
* See also MC13A/B in the Harwell subroutine library (Iain S. Duff and John
* K. Reid, "Algorithm 529: permutations to block triangular form," ACM Trans.
* on Mathematical Software, vol. 4, no. 2, pp. 189-192, 1978, and "An
* implementation of Tarjan's algorithm for the block triangular form of a
* matrix," same journal, pp. 137-147. This code is implements the same
* algorithm as MC13A/B, except that the data structures are very different.
* Also, unlike MC13A/B, the output permutation preserves the natural ordering
* within each block.
*/
static void dfs
(
/* inputs, not modified on output: */
Int j, /* start the DFS at node j */
Int Ap [ ], /* size n+1, column pointers for the matrix A */
Int Ai [ ], /* row indices, size nz = Ap [n] */
Int Q [ ], /* input column permutation */
/* inputs, modified on output (each array is of size n): */
Int Time [ ], /* Time [j] = "time" that node j was first visited */
Int Flag [ ], /* Flag [j]: see above */
Int Low [ ], /* Low [j]: see definition below */
Int *p_nblocks, /* number of blocks (aka strongly-connected-comp.)*/
Int *p_timestamp, /* current "time" */
/* workspace, not defined on input or output: */
Int Cstack [ ], /* size n, output stack to hold nodes of components */
Int Jstack [ ], /* size n, stack for the variable j */
Int Pstack [ ] /* size n, stack for the variable p */
)
{
/* ---------------------------------------------------------------------- */
/* local variables, and initializations */
/* ---------------------------------------------------------------------- */
/* local variables, but "global" to all DFS levels: */
Int chead ; /* top of Cstack */
Int jhead ; /* top of Jstack and Pstack */
/* variables that are purely local to any one DFS level: */
Int i ; /* edge (j,i) considered; i can be next node to traverse */
Int parent ; /* parent of node j in the DFS tree */
Int pend ; /* one past the end of the adjacency list for node j */
Int jj ; /* column j of A*Q is column jj of the input matrix A */
/* variables that need to be pushed then popped from the stack: */
Int p ; /* current index into the adj. list for node j */
/* the variables j and p are stacked in Jstack and Pstack */
/* local copies of variables in the calling routine */
Int nblocks = *p_nblocks ;
Int timestamp = *p_timestamp ;
/* ---------------------------------------------------------------------- */
/* start a DFS at node j (same as the recursive call dfs (EMPTY, j)) */
/* ---------------------------------------------------------------------- */
chead = 0 ; /* component stack is empty */
jhead = 0 ; /* Jstack and Pstack are empty */
Jstack [0] = j ; /* put the first node j on the Jstack */
ASSERT (Flag [j] == UNVISITED) ;
while (jhead >= 0)
{
j = Jstack [jhead] ; /* grab the node j from the top of Jstack */
/* determine which column jj of the A is column j of A*Q */
jj = (Q == (Int *) NULL) ? (j) : (BTF_UNFLIP (Q [j])) ;
pend = Ap [jj+1] ; /* j's row index list ends at Ai [pend-1] */
if (Flag [j] == UNVISITED)
{
/* -------------------------------------------------------------- */
/* prework at node j */
/* -------------------------------------------------------------- */
/* node j is being visited for the first time */
Cstack [++chead] = j ; /* push j onto the stack */
timestamp++ ; /* get a timestamp */
Time [j] = timestamp ; /* give the timestamp to node j */
Low [j] = timestamp ;
Flag [j] = UNASSIGNED ; /* flag node j as visited */
/* -------------------------------------------------------------- */
/* set Pstack [jhead] to the first entry in column j to scan */
/* -------------------------------------------------------------- */
Pstack [jhead] = Ap [jj] ;
}
/* ------------------------------------------------------------------ */
/* DFS rooted at node j (start it, or continue where left off) */
/* ------------------------------------------------------------------ */
for (p = Pstack [jhead] ; p < pend ; p++)
{
i = Ai [p] ; /* examine the edge from node j to node i */
if (Flag [i] == UNVISITED)
{
/* Node i has not been visited - start a DFS at node i.
* Keep track of where we left off in the scan of adjacency list
* of node j so we can restart j where we left off. */
Pstack [jhead] = p + 1 ;
/* Push i onto the stack and immediately break
* so we can recurse on node i. */
Jstack [++jhead] = i ;
ASSERT (Time [i] == EMPTY) ;
ASSERT (Low [i] == EMPTY) ;
/* break here to do what the recursive call dfs (j,i) does */
break ;
}
else if (Flag [i] == UNASSIGNED)
{
/* Node i has been visited, but still unassigned to a block
* this is a back or cross edge if Time [i] < Time [j].
* Note that i might equal j, in which case this code does
* nothing. */
ASSERT (Time [i] > 0) ;
ASSERT (Low [i] > 0) ;
Low [j] = MIN (Low [j], Time [i]) ;
}
}
if (p == pend)
{
/* If all adjacent nodes of j are already visited, pop j from
* Jstack and do the post work for node j. This also pops p
* from the Pstack. */
jhead-- ;
/* -------------------------------------------------------------- */
/* postwork at node j */
/* -------------------------------------------------------------- */
/* determine if node j is the head of a component */
if (Low [j] == Time [j])
{
/* pop all nodes in this SCC from Cstack */
while (TRUE)
{
ASSERT (chead >= 0) ; /* stack not empty (j in it) */
i = Cstack [chead--] ; /* pop a node from the Cstack */
ASSERT (i >= 0) ;
ASSERT (Flag [i] == UNASSIGNED) ;
Flag [i] = nblocks ; /* assign i to current block */
if (i == j) break ; /* current block ends at j */
}
nblocks++ ; /* one more block has been found */
}
/* update Low [parent], if the parent exists */
if (jhead >= 0)
{
parent = Jstack [jhead] ;
Low [parent] = MIN (Low [parent], Low [j]) ;
}
}
}
/* ---------------------------------------------------------------------- */
/* cleanup: update timestamp and nblocks */
/* ---------------------------------------------------------------------- */
*p_timestamp = timestamp ;
*p_nblocks = nblocks ;
}
#else
/* ========================================================================== */
/* === dfs: recursive version (only for illustration) ======================= */
/* ========================================================================== */
/* The following is a recursive version of dfs, which computes identical results
* as the non-recursive dfs. It is included here because it is easier to read.
* Compare the comments in the code below with the identical comments in the
* non-recursive code above, and that will help you see the correlation between
* the two routines.
*
* This routine can cause stack overflow, and is thus not recommended for heavy
* usage, particularly for large matrices. To help in delaying stack overflow,
* global variables are used, reducing the amount of information each call to
* dfs places on the call/return stack (the integers i, j, p, parent, and the
* return address). Note that this means the recursive code is not thread-safe.
* To try this version, compile the code with -DRECURSIVE or include the
* following line at the top of this file:
#define RECURSIVE
*/
static Int /* for recursive illustration only, not for production use */
chead, timestamp, nblocks, n, *Ap, *Ai, *Flag, *Cstack, *Time, *Low,
*P, *R, *Q ;
static void dfs
(
Int parent, /* came from parent node */
Int j /* at node j in the DFS */
)
{
Int p ; /* current index into the adj. list for node j */
Int i ; /* edge (j,i) considered; i can be next node to traverse */
Int jj ; /* column j of A*Q is column jj of the input matrix A */
/* ---------------------------------------------------------------------- */
/* prework at node j */
/* ---------------------------------------------------------------------- */
/* node j is being visited for the first time */
Cstack [++chead] = j ; /* push j onto the stack */
timestamp++ ; /* get a timestamp */
Time [j] = timestamp ; /* give the timestamp to node j */
Low [j] = timestamp ;
Flag [j] = UNASSIGNED ; /* flag node j as visited */
/* ---------------------------------------------------------------------- */
/* DFS rooted at node j */
/* ---------------------------------------------------------------------- */
/* determine which column jj of the A is column j of A*Q */
jj = (Q == (Int *) NULL) ? (j) : (BTF_UNFLIP (Q [j])) ;
for (p = Ap [jj] ; p < Ap [jj+1] ; p++)
{
i = Ai [p] ; /* examine the edge from node j to node i */
if (Flag [i] == UNVISITED)
{
/* Node i has not been visited - start a DFS at node i. */
dfs (j, i) ;
}
else if (Flag [i] == UNASSIGNED)
{
/* Node i has been visited, but still unassigned to a block
* this is a back or cross edge if Time [i] < Time [j].
* Note that i might equal j, in which case this code does
* nothing. */
Low [j] = MIN (Low [j], Time [i]) ;
}
}
/* ---------------------------------------------------------------------- */
/* postwork at node j */
/* ---------------------------------------------------------------------- */
/* determine if node j is the head of a component */
if (Low [j] == Time [j])
{
/* pop all nodes in this strongly connected component from Cstack */
while (TRUE)
{
i = Cstack [chead--] ; /* pop a node from the Cstack */
Flag [i] = nblocks ; /* assign node i to current block */
if (i == j) break ; /* current block ends at node j */
}
nblocks++ ; /* one more block has been found */
}
/* update Low [parent] */
if (parent != EMPTY)
{
/* Note that this could be done with Low[j] = MIN(Low[j],Low[i]) just
* after the dfs (j,i) statement above, and then parent would not have
* to be an input argument. Putting it here places all the postwork
* for node j in one place, thus making the non-recursive DFS easier. */
Low [parent] = MIN (Low [parent], Low [j]) ;
}
}
#endif
/* ========================================================================== */
/* === btf_strongcomp ======================================================= */
/* ========================================================================== */
#ifndef RECURSIVE
Int BTF(strongcomp) /* return # of strongly connected components */
(
/* input, not modified: */
Int n, /* A is n-by-n in compressed column form */
Int Ap [ ], /* size n+1 */
Int Ai [ ], /* size nz = Ap [n] */
/* optional input, modified (if present) on output: */
Int Q [ ], /* size n, input column permutation. The permutation Q can
* include a flag which indicates an unmatched row.
* jold = BTF_UNFLIP (Q [jnew]) is the permutation;
* this function ingnores these flags. On output, it is
* modified according to the permutation P. */
/* output, not defined on input: */
Int P [ ], /* size n. P [k] = j if row and column j are kth row/col
* in permuted matrix. */
Int R [ ], /* size n+1. kth block is in rows/cols R[k] ... R[k+1]-1
* of the permuted matrix. */
/* workspace, not defined on input or output: */
Int Work [ ] /* size 4n */
)
#else
Int BTF(strongcomp) /* recursive version - same as above except for Work size */
(
Int n_in,
Int Ap_in [ ],
Int Ai_in [ ],
Int Q_in [ ],
Int P_in [ ],
Int R_in [ ],
Int Work [ ] /* size 2n */
)
#endif
{
Int j, k, b ;
#ifndef RECURSIVE
Int timestamp, nblocks, *Flag, *Cstack, *Time, *Low, *Jstack, *Pstack ;
#else
n = n_in ;
Ap = Ap_in ;
Ai = Ai_in ;
Q = Q_in ;
P = P_in ;
R = R_in ;
chead = EMPTY ;
#endif
/* ---------------------------------------------------------------------- */
/* get and initialize workspace */
/* ---------------------------------------------------------------------- */
/* timestamp is incremented each time a new node is visited.
*
* Time [j] is the timestamp given to node j.
*
* Low [j] is the lowest timestamp of any node reachable from j via either
* a path to any descendent of j in the DFS tree, or via a single edge to
* an either an ancestor (a back edge) or another node that's neither an
* ancestor nor a descendant (a cross edge). If Low [j] is equal to
* the timestamp of node j (Time [j]), then node j is the "head" of a
* strongly connected component (SCC). That is, it is the first node
* visited in its strongly connected component, and the DFS subtree rooted
* at node j spans all the nodes of the strongly connected component.
*
* The term "block" and "component" are used interchangebly in this code;
* "block" being a matrix term and "component" being a graph term for the
* same thing.
*
* When a node is visited, it is placed on the Cstack (for "component"
* stack). When node j is found to be an SCC head, all the nodes from the
* top of the stack to node j itself form the nodes in the SCC. This Cstack
* is used for both the recursive and non-recursive versions.
*/
Time = Work ; Work += n ;
Flag = Work ; Work += n ;
Low = P ; /* use output array P as workspace for Low */
Cstack = R ; /* use output array R as workspace for Cstack */
#ifndef RECURSIVE
/* stack for non-recursive dfs */
Jstack = Work ; Work += n ; /* stack for j */
Pstack = Work ; /* stack for p */
#endif
for (j = 0 ; j < n ; j++)
{
Flag [j] = UNVISITED ;
Low [j] = EMPTY ;
Time [j] = EMPTY ;
#ifndef NDEBUG
Cstack [j] = EMPTY ;
#ifndef RECURSIVE
Jstack [j] = EMPTY ;
Pstack [j] = EMPTY ;
#endif
#endif
}
timestamp = 0 ; /* each node given a timestamp when it is visited */
nblocks = 0 ; /* number of blocks found so far */
/* ---------------------------------------------------------------------- */
/* find the connected components via a depth-first-search */
/* ---------------------------------------------------------------------- */
for (j = 0 ; j < n ; j++)
{
/* node j is unvisited or assigned to a block. Cstack is empty. */
ASSERT (Flag [j] == UNVISITED || (Flag [j] >= 0 && Flag [j] < nblocks));
if (Flag [j] == UNVISITED)
{
#ifndef RECURSIVE
/* non-recursive dfs (default) */
dfs (j, Ap, Ai, Q, Time, Flag, Low, &nblocks, &timestamp,
Cstack, Jstack, Pstack) ;
#else
/* recursive dfs (for illustration only) */
ASSERT (chead == EMPTY) ;
dfs (EMPTY, j) ;
ASSERT (chead == EMPTY) ;
#endif
}
}
ASSERT (timestamp == n) ;
/* ---------------------------------------------------------------------- */
/* construct the block boundary array, R */
/* ---------------------------------------------------------------------- */
for (b = 0 ; b < nblocks ; b++)
{
R [b] = 0 ;
}
for (j = 0 ; j < n ; j++)
{
/* node j has been assigned to block b = Flag [j] */
ASSERT (Time [j] > 0 && Time [j] <= n) ;
ASSERT (Low [j] > 0 && Low [j] <= n) ;
ASSERT (Flag [j] >= 0 && Flag [j] < nblocks) ;
R [Flag [j]]++ ;
}
/* R [b] is now the number of nodes in block b. Compute cumulative sum
* of R, using Time [0 ... nblocks-1] as workspace. */
Time [0] = 0 ;
for (b = 1 ; b < nblocks ; b++)
{
Time [b] = Time [b-1] + R [b-1] ;
}
for (b = 0 ; b < nblocks ; b++)
{
R [b] = Time [b] ;
}
R [nblocks] = n ;
/* ---------------------------------------------------------------------- */
/* construct the permutation, preserving the natural order */
/* ---------------------------------------------------------------------- */
#ifndef NDEBUG
for (k = 0 ; k < n ; k++)
{
P [k] = EMPTY ;
}
#endif
for (j = 0 ; j < n ; j++)
{
/* place column j in the permutation */
P [Time [Flag [j]]++] = j ;
}
#ifndef NDEBUG
for (k = 0 ; k < n ; k++)
{
ASSERT (P [k] != EMPTY) ;
}
#endif
/* Now block b consists of the nodes k1 to k2-1 in the permuted matrix,
* where k1 = R [b] and k2 = R [b+1]. Row and column j of the original
* matrix becomes row and column P [k] of the permuted matrix. The set of
* of rows/columns (nodes) in block b is given by P [k1 ... k2-1], and this
* set is sorted in ascending order. Thus, if the matrix consists of just
* one block, P is the identity permutation. */
/* ---------------------------------------------------------------------- */
/* if Q is present on input, set Q = Q*P' */
/* ---------------------------------------------------------------------- */
if (Q != (Int *) NULL)
{
/* We found a symmetric permutation P for the matrix A*Q. The overall
* permutation is thus P*(A*Q)*P'. Set Q=Q*P' so that the final
* permutation is P*A*Q. Use Time as workspace. Note that this
* preserves the negative values of Q if the matrix is structurally
* singular. */
for (k = 0 ; k < n ; k++)
{
Time [k] = Q [P [k]] ;
}
for (k = 0 ; k < n ; k++)
{
Q [k] = Time [k] ;
}
}
/* ---------------------------------------------------------------------- */
/* how to traverse the permuted matrix */
/* ---------------------------------------------------------------------- */
/* If Q is not present, the following code can be used to traverse the
* permuted matrix P*A*P'
*
* // compute the inverse of P
* for (knew = 0 ; knew < n ; knew++)
* {
* // row and column kold in the old matrix is row/column knew
* // in the permuted matrix P*A*P'
* kold = P [knew] ;
* Pinv [kold] = knew ;
* }
* for (b = 0 ; b < nblocks ; b++)
* {
* // traverse block b of the permuted matrix P*A*P'
* k1 = R [b] ;
* k2 = R [b+1] ;
* nk = k2 - k1 ;
* for (jnew = k1 ; jnew < k2 ; jnew++)
* {
* jold = P [jnew] ;
* for (p = Ap [jold] ; p < Ap [jold+1] ; p++)
* {
* iold = Ai [p] ;
* inew = Pinv [iold] ;
* // Entry in the old matrix is A (iold, jold), and its
* // position in the new matrix P*A*P' is (inew, jnew).
* // Let B be the bth diagonal block of the permuted
* // matrix. If inew >= k1, then this entry is in row/
* // column (inew-k1, jnew-k1) of the nk-by-nk matrix B.
* // Otherwise, the entry is in the upper block triangular
* // part, not in any diagonal block.
* }
* }
* }
*
* If Q is present replace the above statement
* jold = P [jnew] ;
* with
* jold = Q [jnew] ;
* or
* jold = BTF_UNFLIP (Q [jnew]) ;
*
* then entry A (iold,jold) in the old (unpermuted) matrix is at (inew,jnew)
* in the permuted matrix P*A*Q. Everything else remains the same as the
* above (simply replace P*A*P' with P*A*Q in the above comments).
*/
/* ---------------------------------------------------------------------- */
/* return # of blocks / # of strongly connected components */
/* ---------------------------------------------------------------------- */
return (nblocks) ;
}

3611
src/maths/KLU/colamd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
/* ========================================================================== */
/* === colamd_global.c ====================================================== */
/* ========================================================================== */
/* ----------------------------------------------------------------------------
* COLAMD, Copyright (C) 2007, Timothy A. Davis.
* See License.txt for the Version 2.1 of the GNU Lesser General Public License
* http://www.cise.ufl.edu/research/sparse
* -------------------------------------------------------------------------- */
/* Global variables for COLAMD */
#ifndef NPRINT
#ifdef MATLAB_MEX_FILE
#include "mex.h"
int (*colamd_printf) (const char *, ...) = mexPrintf ;
#else
#include <stdio.h>
int (*colamd_printf) (const char *, ...) = printf ;
#endif
#else
int (*colamd_printf) (const char *, ...) = ((void *) 0) ;
#endif

773
src/maths/KLU/klu.c Normal file
View File

@ -0,0 +1,773 @@
/* ========================================================================== */
/* === klu ================================================================== */
/* ========================================================================== */
/* KLU: factorizes P*A into L*U, using the Gilbert-Peierls algorithm [1], with
* optional symmetric pruning by Eisenstat and Liu [2]. The code is by Tim
* Davis. This algorithm is what appears as the default sparse LU routine in
* MATLAB version 6.0, and still appears in MATLAB 6.5 as [L,U,P] = lu (A).
* Note that no column ordering is provided (see COLAMD or AMD for suitable
* orderings). SuperLU is based on this algorithm, except that it adds the
* use of dense matrix operations on "supernodes" (adjacent columns with
* identical). This code doesn't use supernodes, thus its name ("Kent" LU,
* as in "Clark Kent", in contrast with Super-LU...). This algorithm is slower
* than SuperLU and UMFPACK for large matrices with lots of nonzeros in their
* factors (such as for most finite-element problems). However, for matrices
* with very sparse LU factors, this algorithm is typically faster than both
* SuperLU and UMFPACK, since in this case there is little chance to exploit
* dense matrix kernels (the BLAS).
*
* Only one block of A is factorized, in the BTF form. The input n is the
* size of the block; k1 is the first row and column in the block.
*
* NOTE: no error checking is done on the inputs. This version is not meant to
* be called directly by the user. Use klu_factor instead.
*
* No fill-reducing ordering is provided. The ordering quality of
* klu_kernel_factor is the responsibility of the caller. The input A must
* pre-permuted to reduce fill-in, or fill-reducing input permutation Q must
* be provided.
*
* The input matrix A must be in compressed-column form, with either sorted
* or unsorted row indices. Row indices for column j of A is in
* Ai [Ap [j] ... Ap [j+1]-1] and the same range of indices in Ax holds the
* numerical values. No duplicate entries are allowed.
*
* Copyright 2004-2009, Tim Davis. All rights reserved. See the README
* file for details on permitted use. Note that no code from The MathWorks,
* Inc, or from SuperLU, or from any other source appears here. The code is
* written from scratch, from the algorithmic description in Gilbert & Peierls'
* and Eisenstat & Liu's journal papers [1,2].
*
* If an input permutation Q is provided, the factorization L*U = A (P,Q)
* is computed, where P is determined by partial pivoting, and Q is the input
* ordering. If the pivot tolerance is less than 1, the "diagonal" entry that
* KLU attempts to choose is the diagonal of A (Q,Q). In other words, the
* input permutation is applied symmetrically to the input matrix. The output
* permutation P includes both the partial pivoting ordering and the input
* permutation. If Q is NULL, then it is assumed to be the identity
* permutation. Q is not modified.
*
* [1] Gilbert, J. R. and Peierls, T., "Sparse Partial Pivoting in Time
* Proportional to Arithmetic Operations," SIAM J. Sci. Stat. Comp.,
* vol 9, pp. 862-874, 1988.
* [2] Eisenstat, S. C. and Liu, J. W. H., "Exploiting Structural Symmetry in
* Unsymmetric Sparse Symbolic Factorization," SIAM J. Matrix Analysis &
* Applic., vol 13, pp. 202-211, 1992.
*/
/* ========================================================================== */
#include "klu_internal.h"
size_t KLU_kernel_factor /* 0 if failure, size of LU if OK */
(
/* inputs, not modified */
Int n, /* A is n-by-n. n must be > 0. */
Int Ap [ ], /* size n+1, column pointers for A */
Int Ai [ ], /* size nz = Ap [n], row indices for A */
Entry Ax [ ], /* size nz, values of A */
Int Q [ ], /* size n, optional column permutation */
double Lsize, /* estimate of number of nonzeros in L */
/* outputs, not defined on input */
Unit **p_LU, /* row indices and values of L and U */
Entry Udiag [ ], /* size n, diagonal of U */
Int Llen [ ], /* size n, column length of L */
Int Ulen [ ], /* size n, column length of U */
Int Lip [ ], /* size n, column pointers for L */
Int Uip [ ], /* size n, column pointers for U */
Int P [ ], /* row permutation, size n */
Int *lnz, /* size of L */
Int *unz, /* size of U */
/* workspace, undefined on input */
Entry *X, /* size n double's, zero on output */
Int *Work, /* size 5n Int's */
/* inputs, not modified on output */
Int k1, /* the block of A is from k1 to k2-1 */
Int PSinv [ ], /* inverse of P from symbolic factorization */
double Rs [ ], /* scale factors for A */
/* inputs, modified on output */
Int Offp [ ], /* off-diagonal matrix (modified by this routine) */
Int Offi [ ],
Entry Offx [ ],
/* --------------- */
KLU_common *Common
)
{
double maxlnz, dunits ;
Unit *LU ;
Int *Pinv, *Lpend, *Stack, *Flag, *Ap_pos, *W ;
Int lsize, usize, anz, ok ;
size_t lusize ;
ASSERT (Common != NULL) ;
/* ---------------------------------------------------------------------- */
/* get control parameters, or use defaults */
/* ---------------------------------------------------------------------- */
n = MAX (1, n) ;
anz = Ap [n+k1] - Ap [k1] ;
if (Lsize <= 0)
{
Lsize = -Lsize ;
Lsize = MAX (Lsize, 1.0) ;
lsize = Lsize * anz + n ;
}
else
{
lsize = Lsize ;
}
usize = lsize ;
lsize = MAX (n+1, lsize) ;
usize = MAX (n+1, usize) ;
maxlnz = (((double) n) * ((double) n) + ((double) n)) / 2. ;
maxlnz = MIN (maxlnz, ((double) INT_MAX)) ;
lsize = MIN (maxlnz, lsize) ;
usize = MIN (maxlnz, usize) ;
PRINTF (("Welcome to klu: n %d anz %d k1 %d lsize %d usize %d maxlnz %g\n",
n, anz, k1, lsize, usize, maxlnz)) ;
/* ---------------------------------------------------------------------- */
/* allocate workspace and outputs */
/* ---------------------------------------------------------------------- */
/* return arguments are not yet assigned */
*p_LU = (Unit *) NULL ;
/* these computations are safe from size_t overflow */
W = Work ;
Pinv = (Int *) W ; W += n ;
Stack = (Int *) W ; W += n ;
Flag = (Int *) W ; W += n ;
Lpend = (Int *) W ; W += n ;
Ap_pos = (Int *) W ; W += n ;
dunits = DUNITS (Int, lsize) + DUNITS (Entry, lsize) +
DUNITS (Int, usize) + DUNITS (Entry, usize) ;
lusize = (size_t) dunits ;
ok = !INT_OVERFLOW (dunits) ;
LU = ok ? KLU_malloc (lusize, sizeof (Unit), Common) : NULL ;
if (LU == NULL)
{
/* out of memory, or problem too large */
Common->status = KLU_OUT_OF_MEMORY ;
lusize = 0 ;
return (lusize) ;
}
/* ---------------------------------------------------------------------- */
/* factorize */
/* ---------------------------------------------------------------------- */
/* with pruning, and non-recursive depth-first-search */
lusize = KLU_kernel (n, Ap, Ai, Ax, Q, lusize,
Pinv, P, &LU, Udiag, Llen, Ulen, Lip, Uip, lnz, unz,
X, Stack, Flag, Ap_pos, Lpend,
k1, PSinv, Rs, Offp, Offi, Offx, Common) ;
/* ---------------------------------------------------------------------- */
/* return LU factors, or return nothing if an error occurred */
/* ---------------------------------------------------------------------- */
if (Common->status < KLU_OK)
{
LU = KLU_free (LU, lusize, sizeof (Unit), Common) ;
lusize = 0 ;
}
*p_LU = LU ;
PRINTF ((" in klu noffdiag %d\n", Common->noffdiag)) ;
return (lusize) ;
}
/* ========================================================================== */
/* === KLU_lsolve =========================================================== */
/* ========================================================================== */
/* Solve Lx=b. Assumes L is unit lower triangular and where the unit diagonal
* entry is NOT stored. Overwrites B with the solution X. B is n-by-nrhs
* and is stored in ROW form with row dimension nrhs. nrhs must be in the
* range 1 to 4. */
void KLU_lsolve
(
/* inputs, not modified: */
Int n,
Int Lip [ ],
Int Llen [ ],
Unit LU [ ],
Int nrhs,
/* right-hand-side on input, solution to Lx=b on output */
Entry X [ ]
)
{
Entry x [4], lik ;
Int *Li ;
Entry *Lx ;
Int k, p, len, i ;
switch (nrhs)
{
case 1:
for (k = 0 ; k < n ; k++)
{
x [0] = X [k] ;
GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ;
/* unit diagonal of L is not stored*/
for (p = 0 ; p < len ; p++)
{
/* X [Li [p]] -= Lx [p] * x [0] ; */
MULT_SUB (X [Li [p]], Lx [p], x [0]) ;
}
}
break ;
case 2:
for (k = 0 ; k < n ; k++)
{
x [0] = X [2*k ] ;
x [1] = X [2*k + 1] ;
GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ;
for (p = 0 ; p < len ; p++)
{
i = Li [p] ;
lik = Lx [p] ;
MULT_SUB (X [2*i], lik, x [0]) ;
MULT_SUB (X [2*i + 1], lik, x [1]) ;
}
}
break ;
case 3:
for (k = 0 ; k < n ; k++)
{
x [0] = X [3*k ] ;
x [1] = X [3*k + 1] ;
x [2] = X [3*k + 2] ;
GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ;
for (p = 0 ; p < len ; p++)
{
i = Li [p] ;
lik = Lx [p] ;
MULT_SUB (X [3*i], lik, x [0]) ;
MULT_SUB (X [3*i + 1], lik, x [1]) ;
MULT_SUB (X [3*i + 2], lik, x [2]) ;
}
}
break ;
case 4:
for (k = 0 ; k < n ; k++)
{
x [0] = X [4*k ] ;
x [1] = X [4*k + 1] ;
x [2] = X [4*k + 2] ;
x [3] = X [4*k + 3] ;
GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ;
for (p = 0 ; p < len ; p++)
{
i = Li [p] ;
lik = Lx [p] ;
MULT_SUB (X [4*i], lik, x [0]) ;
MULT_SUB (X [4*i + 1], lik, x [1]) ;
MULT_SUB (X [4*i + 2], lik, x [2]) ;
MULT_SUB (X [4*i + 3], lik, x [3]) ;
}
}
break ;
}
}
/* ========================================================================== */
/* === KLU_usolve =========================================================== */
/* ========================================================================== */
/* Solve Ux=b. Assumes U is non-unit upper triangular and where the diagonal
* entry is NOT stored. Overwrites B with the solution X. B is n-by-nrhs
* and is stored in ROW form with row dimension nrhs. nrhs must be in the
* range 1 to 4. */
void KLU_usolve
(
/* inputs, not modified: */
Int n,
Int Uip [ ],
Int Ulen [ ],
Unit LU [ ],
Entry Udiag [ ],
Int nrhs,
/* right-hand-side on input, solution to Ux=b on output */
Entry X [ ]
)
{
Entry x [4], uik, ukk ;
Int *Ui ;
Entry *Ux ;
Int k, p, len, i ;
switch (nrhs)
{
case 1:
for (k = n-1 ; k >= 0 ; k--)
{
GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ;
/* x [0] = X [k] / Udiag [k] ; */
DIV (x [0], X [k], Udiag [k]) ;
X [k] = x [0] ;
for (p = 0 ; p < len ; p++)
{
/* X [Ui [p]] -= Ux [p] * x [0] ; */
MULT_SUB (X [Ui [p]], Ux [p], x [0]) ;
}
}
break ;
case 2:
for (k = n-1 ; k >= 0 ; k--)
{
GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ;
ukk = Udiag [k] ;
/* x [0] = X [2*k ] / ukk ;
x [1] = X [2*k + 1] / ukk ; */
DIV (x [0], X [2*k], ukk) ;
DIV (x [1], X [2*k + 1], ukk) ;
X [2*k ] = x [0] ;
X [2*k + 1] = x [1] ;
for (p = 0 ; p < len ; p++)
{
i = Ui [p] ;
uik = Ux [p] ;
/* X [2*i ] -= uik * x [0] ;
X [2*i + 1] -= uik * x [1] ; */
MULT_SUB (X [2*i], uik, x [0]) ;
MULT_SUB (X [2*i + 1], uik, x [1]) ;
}
}
break ;
case 3:
for (k = n-1 ; k >= 0 ; k--)
{
GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ;
ukk = Udiag [k] ;
DIV (x [0], X [3*k], ukk) ;
DIV (x [1], X [3*k + 1], ukk) ;
DIV (x [2], X [3*k + 2], ukk) ;
X [3*k ] = x [0] ;
X [3*k + 1] = x [1] ;
X [3*k + 2] = x [2] ;
for (p = 0 ; p < len ; p++)
{
i = Ui [p] ;
uik = Ux [p] ;
MULT_SUB (X [3*i], uik, x [0]) ;
MULT_SUB (X [3*i + 1], uik, x [1]) ;
MULT_SUB (X [3*i + 2], uik, x [2]) ;
}
}
break ;
case 4:
for (k = n-1 ; k >= 0 ; k--)
{
GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ;
ukk = Udiag [k] ;
DIV (x [0], X [4*k], ukk) ;
DIV (x [1], X [4*k + 1], ukk) ;
DIV (x [2], X [4*k + 2], ukk) ;
DIV (x [3], X [4*k + 3], ukk) ;
X [4*k ] = x [0] ;
X [4*k + 1] = x [1] ;
X [4*k + 2] = x [2] ;
X [4*k + 3] = x [3] ;
for (p = 0 ; p < len ; p++)
{
i = Ui [p] ;
uik = Ux [p] ;
MULT_SUB (X [4*i], uik, x [0]) ;
MULT_SUB (X [4*i + 1], uik, x [1]) ;
MULT_SUB (X [4*i + 2], uik, x [2]) ;
MULT_SUB (X [4*i + 3], uik, x [3]) ;
}
}
break ;
}
}
/* ========================================================================== */
/* === KLU_ltsolve ========================================================== */
/* ========================================================================== */
/* Solve L'x=b. Assumes L is unit lower triangular and where the unit diagonal
* entry is NOT stored. Overwrites B with the solution X. B is n-by-nrhs
* and is stored in ROW form with row dimension nrhs. nrhs must in the
* range 1 to 4. */
void KLU_ltsolve
(
/* inputs, not modified: */
Int n,
Int Lip [ ],
Int Llen [ ],
Unit LU [ ],
Int nrhs,
#ifdef COMPLEX
Int conj_solve,
#endif
/* right-hand-side on input, solution to L'x=b on output */
Entry X [ ]
)
{
Entry x [4], lik ;
Int *Li ;
Entry *Lx ;
Int k, p, len, i ;
switch (nrhs)
{
case 1:
for (k = n-1 ; k >= 0 ; k--)
{
GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ;
x [0] = X [k] ;
for (p = 0 ; p < len ; p++)
{
#ifdef COMPLEX
if (conj_solve)
{
/* x [0] -= CONJ (Lx [p]) * X [Li [p]] ; */
MULT_SUB_CONJ (x [0], X [Li [p]], Lx [p]) ;
}
else
#endif
{
/*x [0] -= Lx [p] * X [Li [p]] ;*/
MULT_SUB (x [0], Lx [p], X [Li [p]]) ;
}
}
X [k] = x [0] ;
}
break ;
case 2:
for (k = n-1 ; k >= 0 ; k--)
{
x [0] = X [2*k ] ;
x [1] = X [2*k + 1] ;
GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ;
for (p = 0 ; p < len ; p++)
{
i = Li [p] ;
#ifdef COMPLEX
if (conj_solve)
{
CONJ (lik, Lx [p]) ;
}
else
#endif
{
lik = Lx [p] ;
}
MULT_SUB (x [0], lik, X [2*i]) ;
MULT_SUB (x [1], lik, X [2*i + 1]) ;
}
X [2*k ] = x [0] ;
X [2*k + 1] = x [1] ;
}
break ;
case 3:
for (k = n-1 ; k >= 0 ; k--)
{
x [0] = X [3*k ] ;
x [1] = X [3*k + 1] ;
x [2] = X [3*k + 2] ;
GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ;
for (p = 0 ; p < len ; p++)
{
i = Li [p] ;
#ifdef COMPLEX
if (conj_solve)
{
CONJ (lik, Lx [p]) ;
}
else
#endif
{
lik = Lx [p] ;
}
MULT_SUB (x [0], lik, X [3*i]) ;
MULT_SUB (x [1], lik, X [3*i + 1]) ;
MULT_SUB (x [2], lik, X [3*i + 2]) ;
}
X [3*k ] = x [0] ;
X [3*k + 1] = x [1] ;
X [3*k + 2] = x [2] ;
}
break ;
case 4:
for (k = n-1 ; k >= 0 ; k--)
{
x [0] = X [4*k ] ;
x [1] = X [4*k + 1] ;
x [2] = X [4*k + 2] ;
x [3] = X [4*k + 3] ;
GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ;
for (p = 0 ; p < len ; p++)
{
i = Li [p] ;
#ifdef COMPLEX
if (conj_solve)
{
CONJ (lik, Lx [p]) ;
}
else
#endif
{
lik = Lx [p] ;
}
MULT_SUB (x [0], lik, X [4*i]) ;
MULT_SUB (x [1], lik, X [4*i + 1]) ;
MULT_SUB (x [2], lik, X [4*i + 2]) ;
MULT_SUB (x [3], lik, X [4*i + 3]) ;
}
X [4*k ] = x [0] ;
X [4*k + 1] = x [1] ;
X [4*k + 2] = x [2] ;
X [4*k + 3] = x [3] ;
}
break ;
}
}
/* ========================================================================== */
/* === KLU_utsolve ========================================================== */
/* ========================================================================== */
/* Solve U'x=b. Assumes U is non-unit upper triangular and where the diagonal
* entry is stored (and appears last in each column of U). Overwrites B
* with the solution X. B is n-by-nrhs and is stored in ROW form with row
* dimension nrhs. nrhs must be in the range 1 to 4. */
void KLU_utsolve
(
/* inputs, not modified: */
Int n,
Int Uip [ ],
Int Ulen [ ],
Unit LU [ ],
Entry Udiag [ ],
Int nrhs,
#ifdef COMPLEX
Int conj_solve,
#endif
/* right-hand-side on input, solution to Ux=b on output */
Entry X [ ]
)
{
Entry x [4], uik, ukk ;
Int k, p, len, i ;
Int *Ui ;
Entry *Ux ;
switch (nrhs)
{
case 1:
for (k = 0 ; k < n ; k++)
{
GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ;
x [0] = X [k] ;
for (p = 0 ; p < len ; p++)
{
#ifdef COMPLEX
if (conj_solve)
{
/* x [0] -= CONJ (Ux [p]) * X [Ui [p]] ; */
MULT_SUB_CONJ (x [0], X [Ui [p]], Ux [p]) ;
}
else
#endif
{
/* x [0] -= Ux [p] * X [Ui [p]] ; */
MULT_SUB (x [0], Ux [p], X [Ui [p]]) ;
}
}
#ifdef COMPLEX
if (conj_solve)
{
CONJ (ukk, Udiag [k]) ;
}
else
#endif
{
ukk = Udiag [k] ;
}
DIV (X [k], x [0], ukk) ;
}
break ;
case 2:
for (k = 0 ; k < n ; k++)
{
GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ;
x [0] = X [2*k ] ;
x [1] = X [2*k + 1] ;
for (p = 0 ; p < len ; p++)
{
i = Ui [p] ;
#ifdef COMPLEX
if (conj_solve)
{
CONJ (uik, Ux [p]) ;
}
else
#endif
{
uik = Ux [p] ;
}
MULT_SUB (x [0], uik, X [2*i]) ;
MULT_SUB (x [1], uik, X [2*i + 1]) ;
}
#ifdef COMPLEX
if (conj_solve)
{
CONJ (ukk, Udiag [k]) ;
}
else
#endif
{
ukk = Udiag [k] ;
}
DIV (X [2*k], x [0], ukk) ;
DIV (X [2*k + 1], x [1], ukk) ;
}
break ;
case 3:
for (k = 0 ; k < n ; k++)
{
GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ;
x [0] = X [3*k ] ;
x [1] = X [3*k + 1] ;
x [2] = X [3*k + 2] ;
for (p = 0 ; p < len ; p++)
{
i = Ui [p] ;
#ifdef COMPLEX
if (conj_solve)
{
CONJ (uik, Ux [p]) ;
}
else
#endif
{
uik = Ux [p] ;
}
MULT_SUB (x [0], uik, X [3*i]) ;
MULT_SUB (x [1], uik, X [3*i + 1]) ;
MULT_SUB (x [2], uik, X [3*i + 2]) ;
}
#ifdef COMPLEX
if (conj_solve)
{
CONJ (ukk, Udiag [k]) ;
}
else
#endif
{
ukk = Udiag [k] ;
}
DIV (X [3*k], x [0], ukk) ;
DIV (X [3*k + 1], x [1], ukk) ;
DIV (X [3*k + 2], x [2], ukk) ;
}
break ;
case 4:
for (k = 0 ; k < n ; k++)
{
GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ;
x [0] = X [4*k ] ;
x [1] = X [4*k + 1] ;
x [2] = X [4*k + 2] ;
x [3] = X [4*k + 3] ;
for (p = 0 ; p < len ; p++)
{
i = Ui [p] ;
#ifdef COMPLEX
if (conj_solve)
{
CONJ (uik, Ux [p]) ;
}
else
#endif
{
uik = Ux [p] ;
}
MULT_SUB (x [0], uik, X [4*i]) ;
MULT_SUB (x [1], uik, X [4*i + 1]) ;
MULT_SUB (x [2], uik, X [4*i + 2]) ;
MULT_SUB (x [3], uik, X [4*i + 3]) ;
}
#ifdef COMPLEX
if (conj_solve)
{
CONJ (ukk, Udiag [k]) ;
}
else
#endif
{
ukk = Udiag [k] ;
}
DIV (X [4*k], x [0], ukk) ;
DIV (X [4*k + 1], x [1], ukk) ;
DIV (X [4*k + 2], x [2], ukk) ;
DIV (X [4*k + 3], x [3], ukk) ;
}
break ;
}
}

488
src/maths/KLU/klu_analyze.c Normal file
View File

@ -0,0 +1,488 @@
/* ========================================================================== */
/* === klu_analyze ========================================================== */
/* ========================================================================== */
/* Order the matrix using BTF (or not), and then AMD, COLAMD, the natural
* ordering, or the user-provided-function on the blocks. Does not support
* using a given ordering (use klu_analyze_given for that case). */
#include "klu_internal.h"
/* ========================================================================== */
/* === analyze_worker ======================================================= */
/* ========================================================================== */
static Int analyze_worker /* returns KLU_OK or < 0 if error */
(
/* inputs, not modified */
Int n, /* A is n-by-n */
Int Ap [ ], /* size n+1, column pointers */
Int Ai [ ], /* size nz, row indices */
Int nblocks, /* # of blocks */
Int Pbtf [ ], /* BTF row permutation */
Int Qbtf [ ], /* BTF col permutation */
Int R [ ], /* size n+1, but only Rbtf [0..nblocks] is used */
Int ordering, /* what ordering to use (0, 1, or 3 for this routine) */
/* output only, not defined on input */
Int P [ ], /* size n */
Int Q [ ], /* size n */
double Lnz [ ], /* size n, but only Lnz [0..nblocks-1] is used */
/* workspace, not defined on input or output */
Int Pblk [ ], /* size maxblock */
Int Cp [ ], /* size maxblock+1 */
Int Ci [ ], /* size MAX (nz+1, Cilen) */
Int Cilen, /* nz+1, or COLAMD_recommend(nz,n,n) for COLAMD */
Int Pinv [ ], /* size maxblock */
/* input/output */
KLU_symbolic *Symbolic,
KLU_common *Common
)
{
double amd_Info [AMD_INFO], lnz, lnz1, flops, flops1 ;
Int k1, k2, nk, k, block, oldcol, pend, newcol, result, pc, p, newrow,
maxnz, nzoff, cstats [COLAMD_STATS], ok, err = KLU_INVALID ;
/* ---------------------------------------------------------------------- */
/* initializations */
/* ---------------------------------------------------------------------- */
/* compute the inverse of Pbtf */
#ifndef NDEBUG
for (k = 0 ; k < n ; k++)
{
P [k] = EMPTY ;
Q [k] = EMPTY ;
Pinv [k] = EMPTY ;
}
#endif
for (k = 0 ; k < n ; k++)
{
ASSERT (Pbtf [k] >= 0 && Pbtf [k] < n) ;
Pinv [Pbtf [k]] = k ;
}
#ifndef NDEBUG
for (k = 0 ; k < n ; k++) ASSERT (Pinv [k] != EMPTY) ;
#endif
nzoff = 0 ;
lnz = 0 ;
maxnz = 0 ;
flops = 0 ;
Symbolic->symmetry = EMPTY ; /* only computed by AMD */
/* ---------------------------------------------------------------------- */
/* order each block */
/* ---------------------------------------------------------------------- */
for (block = 0 ; block < nblocks ; block++)
{
/* ------------------------------------------------------------------ */
/* the block is from rows/columns k1 to k2-1 */
/* ------------------------------------------------------------------ */
k1 = R [block] ;
k2 = R [block+1] ;
nk = k2 - k1 ;
PRINTF (("BLOCK %d, k1 %d k2-1 %d nk %d\n", block, k1, k2-1, nk)) ;
/* ------------------------------------------------------------------ */
/* construct the kth block, C */
/* ------------------------------------------------------------------ */
Lnz [block] = EMPTY ;
pc = 0 ;
for (k = k1 ; k < k2 ; k++)
{
newcol = k-k1 ;
Cp [newcol] = pc ;
oldcol = Qbtf [k] ;
pend = Ap [oldcol+1] ;
for (p = Ap [oldcol] ; p < pend ; p++)
{
newrow = Pinv [Ai [p]] ;
if (newrow < k1)
{
nzoff++ ;
}
else
{
/* (newrow,newcol) is an entry in the block */
ASSERT (newrow < k2) ;
newrow -= k1 ;
Ci [pc++] = newrow ;
}
}
}
Cp [nk] = pc ;
maxnz = MAX (maxnz, pc) ;
ASSERT (KLU_valid (nk, Cp, Ci, NULL)) ;
/* ------------------------------------------------------------------ */
/* order the block C */
/* ------------------------------------------------------------------ */
if (nk <= 3)
{
/* -------------------------------------------------------------- */
/* use natural ordering for tiny blocks (3-by-3 or less) */
/* -------------------------------------------------------------- */
for (k = 0 ; k < nk ; k++)
{
Pblk [k] = k ;
}
lnz1 = nk * (nk + 1) / 2 ;
flops1 = nk * (nk - 1) / 2 + (nk-1)*nk*(2*nk-1) / 6 ;
ok = TRUE ;
}
else if (ordering == 0)
{
/* -------------------------------------------------------------- */
/* order the block with AMD (C+C') */
/* -------------------------------------------------------------- */
result = AMD_order (nk, Cp, Ci, Pblk, NULL, amd_Info) ;
ok = (result >= AMD_OK) ;
if (result == AMD_OUT_OF_MEMORY)
{
err = KLU_OUT_OF_MEMORY ;
}
/* account for memory usage in AMD */
Common->mempeak = MAX (Common->mempeak,
Common->memusage + amd_Info [AMD_MEMORY]) ;
/* get the ordering statistics from AMD */
lnz1 = (Int) (amd_Info [AMD_LNZ]) + nk ;
flops1 = 2 * amd_Info [AMD_NMULTSUBS_LU] + amd_Info [AMD_NDIV] ;
if (pc == maxnz)
{
/* get the symmetry of the biggest block */
Symbolic->symmetry = amd_Info [AMD_SYMMETRY] ;
}
}
else if (ordering == 1)
{
/* -------------------------------------------------------------- */
/* order the block with COLAMD (C) */
/* -------------------------------------------------------------- */
/* order (and destroy) Ci, returning column permutation in Cp.
* COLAMD "cannot" fail since the matrix has already been checked,
* and Ci allocated. */
ok = COLAMD (nk, nk, Cilen, Ci, Cp, NULL, cstats) ;
lnz1 = EMPTY ;
flops1 = EMPTY ;
/* copy the permutation from Cp to Pblk */
for (k = 0 ; k < nk ; k++)
{
Pblk [k] = Cp [k] ;
}
}
else
{
/* -------------------------------------------------------------- */
/* pass the block to the user-provided ordering function */
/* -------------------------------------------------------------- */
lnz1 = (Common->user_order) (nk, Cp, Ci, Pblk, Common) ;
flops1 = EMPTY ;
ok = (lnz1 != 0) ;
}
if (!ok)
{
return (err) ; /* ordering method failed */
}
/* ------------------------------------------------------------------ */
/* keep track of nnz(L) and flops statistics */
/* ------------------------------------------------------------------ */
Lnz [block] = lnz1 ;
lnz = (lnz == EMPTY || lnz1 == EMPTY) ? EMPTY : (lnz + lnz1) ;
flops = (flops == EMPTY || flops1 == EMPTY) ? EMPTY : (flops + flops1) ;
/* ------------------------------------------------------------------ */
/* combine the preordering with the BTF ordering */
/* ------------------------------------------------------------------ */
PRINTF (("Pblk, 1-based:\n")) ;
for (k = 0 ; k < nk ; k++)
{
ASSERT (k + k1 < n) ;
ASSERT (Pblk [k] + k1 < n) ;
Q [k + k1] = Qbtf [Pblk [k] + k1] ;
}
for (k = 0 ; k < nk ; k++)
{
ASSERT (k + k1 < n) ;
ASSERT (Pblk [k] + k1 < n) ;
P [k + k1] = Pbtf [Pblk [k] + k1] ;
}
}
PRINTF (("nzoff %d Ap[n] %d\n", nzoff, Ap [n])) ;
ASSERT (nzoff >= 0 && nzoff <= Ap [n]) ;
/* return estimates of # of nonzeros in L including diagonal */
Symbolic->lnz = lnz ; /* EMPTY if COLAMD used */
Symbolic->unz = lnz ;
Symbolic->nzoff = nzoff ;
Symbolic->est_flops = flops ; /* EMPTY if COLAMD or user-ordering used */
return (KLU_OK) ;
}
/* ========================================================================== */
/* === order_and_analyze ==================================================== */
/* ========================================================================== */
/* Orders the matrix with or with BTF, then orders each block with AMD, COLAMD,
* or the user ordering function. Does not handle the natural or given
* ordering cases. */
static KLU_symbolic *order_and_analyze /* returns NULL if error, or a valid
KLU_symbolic object if successful */
(
/* inputs, not modified */
Int n, /* A is n-by-n */
Int Ap [ ], /* size n+1, column pointers */
Int Ai [ ], /* size nz, row indices */
/* --------------------- */
KLU_common *Common
)
{
double work ;
KLU_symbolic *Symbolic ;
double *Lnz ;
Int *Qbtf, *Cp, *Ci, *Pinv, *Pblk, *Pbtf, *P, *Q, *R ;
Int nblocks, nz, block, maxblock, k1, k2, nk, do_btf, ordering, k, Cilen,
*Work ;
/* ---------------------------------------------------------------------- */
/* allocate the Symbolic object, and check input matrix */
/* ---------------------------------------------------------------------- */
Symbolic = KLU_alloc_symbolic (n, Ap, Ai, Common) ;
if (Symbolic == NULL)
{
return (NULL) ;
}
P = Symbolic->P ;
Q = Symbolic->Q ;
R = Symbolic->R ;
Lnz = Symbolic->Lnz ;
nz = Symbolic->nz ;
ordering = Common->ordering ;
if (ordering == 1)
{
/* COLAMD */
Cilen = COLAMD_recommended (nz, n, n) ;
}
else if (ordering == 0 || (ordering == 3 && Common->user_order != NULL))
{
/* AMD or user ordering function */
Cilen = nz+1 ;
}
else
{
/* invalid ordering */
Common->status = KLU_INVALID ;
KLU_free_symbolic (&Symbolic, Common) ;
return (NULL) ;
}
/* AMD memory management routines */
amd_malloc = Common->malloc_memory ;
amd_free = Common->free_memory ;
amd_calloc = Common->calloc_memory ;
amd_realloc = Common->realloc_memory ;
/* ---------------------------------------------------------------------- */
/* allocate workspace for BTF permutation */
/* ---------------------------------------------------------------------- */
Pbtf = KLU_malloc (n, sizeof (Int), Common) ;
Qbtf = KLU_malloc (n, sizeof (Int), Common) ;
if (Common->status < KLU_OK)
{
KLU_free (Pbtf, n, sizeof (Int), Common) ;
KLU_free (Qbtf, n, sizeof (Int), Common) ;
KLU_free_symbolic (&Symbolic, Common) ;
return (NULL) ;
}
/* ---------------------------------------------------------------------- */
/* get the common parameters for BTF and ordering method */
/* ---------------------------------------------------------------------- */
do_btf = Common->btf ;
do_btf = (do_btf) ? TRUE : FALSE ;
Symbolic->ordering = ordering ;
Symbolic->do_btf = do_btf ;
Symbolic->structural_rank = EMPTY ;
/* ---------------------------------------------------------------------- */
/* find the block triangular form (if requested) */
/* ---------------------------------------------------------------------- */
Common->work = 0 ;
if (do_btf)
{
Work = KLU_malloc (5*n, sizeof (Int), Common) ;
if (Common->status < KLU_OK)
{
/* out of memory */
KLU_free (Pbtf, n, sizeof (Int), Common) ;
KLU_free (Qbtf, n, sizeof (Int), Common) ;
KLU_free_symbolic (&Symbolic, Common) ;
return (NULL) ;
}
nblocks = BTF_order (n, Ap, Ai, Common->maxwork, &work, Pbtf, Qbtf, R,
&(Symbolic->structural_rank), Work) ;
Common->structural_rank = Symbolic->structural_rank ;
Common->work += work ;
KLU_free (Work, 5*n, sizeof (Int), Common) ;
/* unflip Qbtf if the matrix does not have full structural rank */
if (Symbolic->structural_rank < n)
{
for (k = 0 ; k < n ; k++)
{
Qbtf [k] = BTF_UNFLIP (Qbtf [k]) ;
}
}
/* find the size of the largest block */
maxblock = 1 ;
for (block = 0 ; block < nblocks ; block++)
{
k1 = R [block] ;
k2 = R [block+1] ;
nk = k2 - k1 ;
PRINTF (("block %d size %d\n", block, nk)) ;
maxblock = MAX (maxblock, nk) ;
}
}
else
{
/* BTF not requested */
nblocks = 1 ;
maxblock = n ;
R [0] = 0 ;
R [1] = n ;
for (k = 0 ; k < n ; k++)
{
Pbtf [k] = k ;
Qbtf [k] = k ;
}
}
Symbolic->nblocks = nblocks ;
PRINTF (("maxblock size %d\n", maxblock)) ;
Symbolic->maxblock = maxblock ;
/* ---------------------------------------------------------------------- */
/* allocate more workspace, for analyze_worker */
/* ---------------------------------------------------------------------- */
Pblk = KLU_malloc (maxblock, sizeof (Int), Common) ;
Cp = KLU_malloc (maxblock + 1, sizeof (Int), Common) ;
Ci = KLU_malloc (MAX (Cilen, nz+1), sizeof (Int), Common) ;
Pinv = KLU_malloc (n, sizeof (Int), Common) ;
/* ---------------------------------------------------------------------- */
/* order each block of the BTF ordering, and a fill-reducing ordering */
/* ---------------------------------------------------------------------- */
if (Common->status == KLU_OK)
{
PRINTF (("calling analyze_worker\n")) ;
Common->status = analyze_worker (n, Ap, Ai, nblocks, Pbtf, Qbtf, R,
ordering, P, Q, Lnz, Pblk, Cp, Ci, Cilen, Pinv, Symbolic, Common) ;
PRINTF (("analyze_worker done\n")) ;
}
/* ---------------------------------------------------------------------- */
/* free all workspace */
/* ---------------------------------------------------------------------- */
KLU_free (Pblk, maxblock, sizeof (Int), Common) ;
KLU_free (Cp, maxblock+1, sizeof (Int), Common) ;
KLU_free (Ci, MAX (Cilen, nz+1), sizeof (Int), Common) ;
KLU_free (Pinv, n, sizeof (Int), Common) ;
KLU_free (Pbtf, n, sizeof (Int), Common) ;
KLU_free (Qbtf, n, sizeof (Int), Common) ;
/* ---------------------------------------------------------------------- */
/* return the symbolic object */
/* ---------------------------------------------------------------------- */
if (Common->status < KLU_OK)
{
KLU_free_symbolic (&Symbolic, Common) ;
}
return (Symbolic) ;
}
/* ========================================================================== */
/* === KLU_analyze ========================================================== */
/* ========================================================================== */
KLU_symbolic *KLU_analyze /* returns NULL if error, or a valid
KLU_symbolic object if successful */
(
/* inputs, not modified */
Int n, /* A is n-by-n */
Int Ap [ ], /* size n+1, column pointers */
Int Ai [ ], /* size nz, row indices */
/* -------------------- */
KLU_common *Common
)
{
/* ---------------------------------------------------------------------- */
/* get the control parameters for BTF and ordering method */
/* ---------------------------------------------------------------------- */
if (Common == NULL)
{
return (NULL) ;
}
Common->status = KLU_OK ;
Common->structural_rank = EMPTY ;
/* ---------------------------------------------------------------------- */
/* order and analyze */
/* ---------------------------------------------------------------------- */
if (Common->ordering == 2)
{
/* natural ordering */
return (KLU_analyze_given (n, Ap, Ai, NULL, NULL, Common)) ;
}
else
{
/* order with P and Q */
return (order_and_analyze (n, Ap, Ai, Common)) ;
}
}

View File

@ -0,0 +1,369 @@
/* ========================================================================== */
/* === klu_analyze_given ==================================================== */
/* ========================================================================== */
/* Given an input permutation P and Q, create the Symbolic object. BTF can
* be done to modify the user's P and Q (does not perform the max transversal;
* just finds the strongly-connected components). */
#include "klu_internal.h"
/* ========================================================================== */
/* === klu_alloc_symbolic =================================================== */
/* ========================================================================== */
/* Allocate Symbolic object, and check input matrix. Not user callable. */
KLU_symbolic *KLU_alloc_symbolic
(
Int n,
Int *Ap,
Int *Ai,
KLU_common *Common
)
{
KLU_symbolic *Symbolic ;
Int *P, *Q, *R ;
double *Lnz ;
Int nz, i, j, p, pend ;
if (Common == NULL)
{
return (NULL) ;
}
Common->status = KLU_OK ;
/* A is n-by-n, with n > 0. Ap [0] = 0 and nz = Ap [n] >= 0 required.
* Ap [j] <= Ap [j+1] must hold for all j = 0 to n-1. Row indices in Ai
* must be in the range 0 to n-1, and no duplicate entries can be present.
* The list of row indices in each column of A need not be sorted.
*/
if (n <= 0 || Ap == NULL || Ai == NULL)
{
/* Ap and Ai must be present, and n must be > 0 */
Common->status = KLU_INVALID ;
return (NULL) ;
}
nz = Ap [n] ;
if (Ap [0] != 0 || nz < 0)
{
/* nz must be >= 0 and Ap [0] must equal zero */
Common->status = KLU_INVALID ;
return (NULL) ;
}
for (j = 0 ; j < n ; j++)
{
if (Ap [j] > Ap [j+1])
{
/* column pointers must be non-decreasing */
Common->status = KLU_INVALID ;
return (NULL) ;
}
}
P = KLU_malloc (n, sizeof (Int), Common) ;
if (Common->status < KLU_OK)
{
/* out of memory */
Common->status = KLU_OUT_OF_MEMORY ;
return (NULL) ;
}
for (i = 0 ; i < n ; i++)
{
P [i] = EMPTY ;
}
for (j = 0 ; j < n ; j++)
{
pend = Ap [j+1] ;
for (p = Ap [j] ; p < pend ; p++)
{
i = Ai [p] ;
if (i < 0 || i >= n || P [i] == j)
{
/* row index out of range, or duplicate entry */
KLU_free (P, n, sizeof (Int), Common) ;
Common->status = KLU_INVALID ;
return (NULL) ;
}
/* flag row i as appearing in column j */
P [i] = j ;
}
}
/* ---------------------------------------------------------------------- */
/* allocate the Symbolic object */
/* ---------------------------------------------------------------------- */
Symbolic = KLU_malloc (sizeof (KLU_symbolic), 1, Common) ;
if (Common->status < KLU_OK)
{
/* out of memory */
KLU_free (P, n, sizeof (Int), Common) ;
Common->status = KLU_OUT_OF_MEMORY ;
return (NULL) ;
}
Q = KLU_malloc (n, sizeof (Int), Common) ;
R = KLU_malloc (n+1, sizeof (Int), Common) ;
Lnz = KLU_malloc (n, sizeof (double), Common) ;
Symbolic->n = n ;
Symbolic->nz = nz ;
Symbolic->P = P ;
Symbolic->Q = Q ;
Symbolic->R = R ;
Symbolic->Lnz = Lnz ;
if (Common->status < KLU_OK)
{
/* out of memory */
KLU_free_symbolic (&Symbolic, Common) ;
Common->status = KLU_OUT_OF_MEMORY ;
return (NULL) ;
}
return (Symbolic) ;
}
/* ========================================================================== */
/* === KLU_analyze_given ==================================================== */
/* ========================================================================== */
KLU_symbolic *KLU_analyze_given /* returns NULL if error, or a valid
KLU_symbolic object if successful */
(
/* inputs, not modified */
Int n, /* A is n-by-n */
Int Ap [ ], /* size n+1, column pointers */
Int Ai [ ], /* size nz, row indices */
Int Puser [ ], /* size n, user's row permutation (may be NULL) */
Int Quser [ ], /* size n, user's column permutation (may be NULL) */
/* -------------------- */
KLU_common *Common
)
{
KLU_symbolic *Symbolic ;
double *Lnz ;
Int nblocks, nz, block, maxblock, *P, *Q, *R, nzoff, p, pend, do_btf, k ;
/* ---------------------------------------------------------------------- */
/* determine if input matrix is valid, and get # of nonzeros */
/* ---------------------------------------------------------------------- */
Symbolic = KLU_alloc_symbolic (n, Ap, Ai, Common) ;
if (Symbolic == NULL)
{
return (NULL) ;
}
P = Symbolic->P ;
Q = Symbolic->Q ;
R = Symbolic->R ;
Lnz = Symbolic->Lnz ;
nz = Symbolic->nz ;
/* ---------------------------------------------------------------------- */
/* Q = Quser, or identity if Quser is NULL */
/* ---------------------------------------------------------------------- */
if (Quser == (Int *) NULL)
{
for (k = 0 ; k < n ; k++)
{
Q [k] = k ;
}
}
else
{
for (k = 0 ; k < n ; k++)
{
Q [k] = Quser [k] ;
}
}
/* ---------------------------------------------------------------------- */
/* get the control parameters for BTF and ordering method */
/* ---------------------------------------------------------------------- */
do_btf = Common->btf ;
do_btf = (do_btf) ? TRUE : FALSE ;
Symbolic->ordering = 2 ;
Symbolic->do_btf = do_btf ;
/* ---------------------------------------------------------------------- */
/* find the block triangular form, if requested */
/* ---------------------------------------------------------------------- */
if (do_btf)
{
/* ------------------------------------------------------------------ */
/* get workspace for BTF_strongcomp */
/* ------------------------------------------------------------------ */
Int *Pinv, *Work, *Bi, k1, k2, nk, oldcol ;
Work = KLU_malloc (4*n, sizeof (Int), Common) ;
Pinv = KLU_malloc (n, sizeof (Int), Common) ;
if (Puser != (Int *) NULL)
{
Bi = KLU_malloc (nz+1, sizeof (Int), Common) ;
}
else
{
Bi = Ai ;
}
if (Common->status < KLU_OK)
{
/* out of memory */
KLU_free (Work, 4*n, sizeof (Int), Common) ;
KLU_free (Pinv, n, sizeof (Int), Common) ;
if (Puser != (Int *) NULL)
{
KLU_free (Bi, nz+1, sizeof (Int), Common) ;
}
KLU_free_symbolic (&Symbolic, Common) ;
Common->status = KLU_OUT_OF_MEMORY ;
return (NULL) ;
}
/* ------------------------------------------------------------------ */
/* B = Puser * A */
/* ------------------------------------------------------------------ */
if (Puser != (Int *) NULL)
{
for (k = 0 ; k < n ; k++)
{
Pinv [Puser [k]] = k ;
}
for (p = 0 ; p < nz ; p++)
{
Bi [p] = Pinv [Ai [p]] ;
}
}
/* ------------------------------------------------------------------ */
/* find the strongly-connected components */
/* ------------------------------------------------------------------ */
/* modifies Q, and determines P and R */
nblocks = BTF_strongcomp (n, Ap, Bi, Q, P, R, Work) ;
/* ------------------------------------------------------------------ */
/* P = P * Puser */
/* ------------------------------------------------------------------ */
if (Puser != (Int *) NULL)
{
for (k = 0 ; k < n ; k++)
{
Work [k] = Puser [P [k]] ;
}
for (k = 0 ; k < n ; k++)
{
P [k] = Work [k] ;
}
}
/* ------------------------------------------------------------------ */
/* Pinv = inverse of P */
/* ------------------------------------------------------------------ */
for (k = 0 ; k < n ; k++)
{
Pinv [P [k]] = k ;
}
/* ------------------------------------------------------------------ */
/* analyze each block */
/* ------------------------------------------------------------------ */
nzoff = 0 ; /* nz in off-diagonal part */
maxblock = 1 ; /* size of the largest block */
for (block = 0 ; block < nblocks ; block++)
{
/* -------------------------------------------------------------- */
/* the block is from rows/columns k1 to k2-1 */
/* -------------------------------------------------------------- */
k1 = R [block] ;
k2 = R [block+1] ;
nk = k2 - k1 ;
PRINTF (("BLOCK %d, k1 %d k2-1 %d nk %d\n", block, k1, k2-1, nk)) ;
maxblock = MAX (maxblock, nk) ;
/* -------------------------------------------------------------- */
/* scan the kth block, C */
/* -------------------------------------------------------------- */
for (k = k1 ; k < k2 ; k++)
{
oldcol = Q [k] ;
pend = Ap [oldcol+1] ;
for (p = Ap [oldcol] ; p < pend ; p++)
{
if (Pinv [Ai [p]] < k1)
{
nzoff++ ;
}
}
}
/* fill-in not estimated */
Lnz [block] = EMPTY ;
}
/* ------------------------------------------------------------------ */
/* free all workspace */
/* ------------------------------------------------------------------ */
KLU_free (Work, 4*n, sizeof (Int), Common) ;
KLU_free (Pinv, n, sizeof (Int), Common) ;
if (Puser != (Int *) NULL)
{
KLU_free (Bi, nz+1, sizeof (Int), Common) ;
}
}
else
{
/* ------------------------------------------------------------------ */
/* BTF not requested */
/* ------------------------------------------------------------------ */
nzoff = 0 ;
nblocks = 1 ;
maxblock = n ;
R [0] = 0 ;
R [1] = n ;
Lnz [0] = EMPTY ;
/* ------------------------------------------------------------------ */
/* P = Puser, or identity if Puser is NULL */
/* ------------------------------------------------------------------ */
for (k = 0 ; k < n ; k++)
{
P [k] = (Puser == NULL) ? k : Puser [k] ;
}
}
/* ---------------------------------------------------------------------- */
/* return the symbolic object */
/* ---------------------------------------------------------------------- */
Symbolic->nblocks = nblocks ;
Symbolic->maxblock = maxblock ;
Symbolic->lnz = EMPTY ;
Symbolic->unz = EMPTY ;
Symbolic->nzoff = nzoff ;
return (Symbolic) ;
}

View File

@ -0,0 +1,60 @@
/* ========================================================================== */
/* === KLU_defaults ========================================================= */
/* ========================================================================== */
/* Sets default parameters for KLU */
#include "klu_internal.h"
Int KLU_defaults
(
KLU_common *Common
)
{
if (Common == NULL)
{
return (FALSE) ;
}
/* parameters */
Common->tol = 0.001 ; /* pivot tolerance for diagonal */
Common->memgrow = 1.2; /* realloc size ratio increase for LU factors */
Common->initmem_amd = 1.2 ; /* init. mem with AMD: c*nnz(L) + n */
Common->initmem = 10 ; /* init. mem otherwise: c*nnz(A) + n */
Common->btf = TRUE ; /* use BTF pre-ordering, or not */
Common->maxwork = 0 ; /* no limit to work done by btf_order */
Common->ordering = 0 ; /* 0: AMD, 1: COLAMD, 2: user-provided P and Q,
* 3: user-provided function */
Common->scale = 2 ; /* scale: -1: none, and do not check for errors
* in the input matrix in KLU_refactor.
* 0: none, but check for errors,
* 1: sum, 2: max */
Common->halt_if_singular = TRUE ; /* quick halt if matrix is singular */
/* memory management routines */
Common->malloc_memory = malloc ;
Common->calloc_memory = calloc ;
Common->free_memory = free ;
Common->realloc_memory = realloc ;
/* user ordering function and optional argument */
Common->user_order = NULL ;
Common->user_data = NULL ;
/* statistics */
Common->status = KLU_OK ;
Common->nrealloc = 0 ;
Common->structural_rank = EMPTY ;
Common->numerical_rank = EMPTY ;
Common->noffdiag = EMPTY ;
Common->flops = EMPTY ;
Common->rcond = EMPTY ;
Common->condest = EMPTY ;
Common->rgrowth = EMPTY ;
Common->work = 0 ; /* work done by btf_order */
Common->memusage = 0 ;
Common->mempeak = 0 ;
return (TRUE) ;
}

View File

@ -0,0 +1,570 @@
/* ========================================================================== */
/* === KLU_diagnostics ====================================================== */
/* ========================================================================== */
/* Linear algebraic diagnostics:
* KLU_rgrowth: reciprocal pivot growth, takes O(|A|+|U|) time
* KLU_condest: condition number estimator, takes about O(|A|+5*(|L|+|U|)) time
* KLU_flops: compute # flops required to factorize A into L*U
* KLU_rcond: compute a really cheap estimate of the reciprocal of the
* condition number, min(abs(diag(U))) / max(abs(diag(U))).
* Takes O(n) time.
*/
#include "klu_internal.h"
/* ========================================================================== */
/* === KLU_rgrowth ========================================================== */
/* ========================================================================== */
/* Compute the reciprocal pivot growth factor. In MATLAB notation:
*
* rgrowth = min (max (abs ((R \ A (p,q)) - F))) ./ max (abs (U)))
*/
Int KLU_rgrowth /* return TRUE if successful, FALSE otherwise */
(
Int *Ap,
Int *Ai,
double *Ax,
KLU_symbolic *Symbolic,
KLU_numeric *Numeric,
KLU_common *Common
)
{
double temp, max_ai, max_ui, min_block_rgrowth ;
Entry aik ;
Int *Q, *Ui, *Uip, *Ulen, *Pinv ;
Unit *LU ;
Entry *Aentry, *Ux, *Ukk ;
double *Rs ;
Int i, newrow, oldrow, k1, k2, nk, j, oldcol, k, pend, len ;
/* ---------------------------------------------------------------------- */
/* check inputs */
/* ---------------------------------------------------------------------- */
if (Common == NULL)
{
return (FALSE) ;
}
if (Symbolic == NULL || Ap == NULL || Ai == NULL || Ax == NULL)
{
Common->status = KLU_INVALID ;
return (FALSE) ;
}
if (Numeric == NULL)
{
/* treat this as a singular matrix */
Common->rgrowth = 0 ;
Common->status = KLU_SINGULAR ;
return (TRUE) ;
}
Common->status = KLU_OK ;
/* ---------------------------------------------------------------------- */
/* compute the reciprocal pivot growth */
/* ---------------------------------------------------------------------- */
Aentry = (Entry *) Ax ;
Pinv = Numeric->Pinv ;
Rs = Numeric->Rs ;
Q = Symbolic->Q ;
Common->rgrowth = 1 ;
for (i = 0 ; i < Symbolic->nblocks ; i++)
{
k1 = Symbolic->R[i] ;
k2 = Symbolic->R[i+1] ;
nk = k2 - k1 ;
if (nk == 1)
{
continue ; /* skip singleton blocks */
}
LU = (Unit *) Numeric->LUbx[i] ;
Uip = Numeric->Uip + k1 ;
Ulen = Numeric->Ulen + k1 ;
Ukk = ((Entry *) Numeric->Udiag) + k1 ;
min_block_rgrowth = 1 ;
for (j = 0 ; j < nk ; j++)
{
max_ai = 0 ;
max_ui = 0 ;
oldcol = Q[j + k1] ;
pend = Ap [oldcol + 1] ;
for (k = Ap [oldcol] ; k < pend ; k++)
{
oldrow = Ai [k] ;
newrow = Pinv [oldrow] ;
if (newrow < k1)
{
continue ; /* skip entry outside the block */
}
ASSERT (newrow < k2) ;
if (Rs != NULL)
{
/* aik = Aentry [k] / Rs [oldrow] */
SCALE_DIV_ASSIGN (aik, Aentry [k], Rs [newrow]) ;
}
else
{
aik = Aentry [k] ;
}
/* temp = ABS (aik) */
ABS (temp, aik) ;
if (temp > max_ai)
{
max_ai = temp ;
}
}
GET_POINTER (LU, Uip, Ulen, Ui, Ux, j, len) ;
for (k = 0 ; k < len ; k++)
{
/* temp = ABS (Ux [k]) */
ABS (temp, Ux [k]) ;
if (temp > max_ui)
{
max_ui = temp ;
}
}
/* consider the diagonal element */
ABS (temp, Ukk [j]) ;
if (temp > max_ui)
{
max_ui = temp ;
}
/* if max_ui is 0, skip the column */
if (SCALAR_IS_ZERO (max_ui))
{
continue ;
}
temp = max_ai / max_ui ;
if (temp < min_block_rgrowth)
{
min_block_rgrowth = temp ;
}
}
if (min_block_rgrowth < Common->rgrowth)
{
Common->rgrowth = min_block_rgrowth ;
}
}
return (TRUE) ;
}
/* ========================================================================== */
/* === KLU_condest ========================================================== */
/* ========================================================================== */
/* Estimate the condition number. Uses Higham and Tisseur's algorithm
* (A block algorithm for matrix 1-norm estimation, with applications to
* 1-norm pseudospectra, SIAM J. Matrix Anal. Appl., 21(4):1185-1201, 2000.
*/
Int KLU_condest /* return TRUE if successful, FALSE otherwise */
(
Int Ap [ ],
double Ax [ ],
KLU_symbolic *Symbolic,
KLU_numeric *Numeric,
KLU_common *Common
)
{
double xj, Xmax, csum, anorm, ainv_norm, est_old, est_new, abs_value ;
Entry *Udiag, *Aentry, *X, *S ;
Int *R ;
Int nblocks, i, j, jmax, jnew, pend, n ;
#ifndef COMPLEX
Int unchanged ;
#endif
/* ---------------------------------------------------------------------- */
/* check inputs */
/* ---------------------------------------------------------------------- */
if (Common == NULL)
{
return (FALSE) ;
}
if (Symbolic == NULL || Ap == NULL || Ax == NULL)
{
Common->status = KLU_INVALID ;
return (FALSE) ;
}
abs_value = 0 ;
if (Numeric == NULL)
{
/* treat this as a singular matrix */
Common->condest = 1 / abs_value ;
Common->status = KLU_SINGULAR ;
return (TRUE) ;
}
Common->status = KLU_OK ;
/* ---------------------------------------------------------------------- */
/* get inputs */
/* ---------------------------------------------------------------------- */
n = Symbolic->n ;
nblocks = Symbolic->nblocks ;
R = Symbolic->R ;
Udiag = Numeric->Udiag ;
/* ---------------------------------------------------------------------- */
/* check if diagonal of U has a zero on it */
/* ---------------------------------------------------------------------- */
for (i = 0 ; i < n ; i++)
{
ABS (abs_value, Udiag [i]) ;
if (SCALAR_IS_ZERO (abs_value))
{
Common->condest = 1 / abs_value ;
Common->status = KLU_SINGULAR ;
return (TRUE) ;
}
}
/* ---------------------------------------------------------------------- */
/* compute 1-norm (maximum column sum) of the matrix */
/* ---------------------------------------------------------------------- */
anorm = 0.0 ;
Aentry = (Entry *) Ax ;
for (i = 0 ; i < n ; i++)
{
pend = Ap [i + 1] ;
csum = 0.0 ;
for (j = Ap [i] ; j < pend ; j++)
{
ABS (abs_value, Aentry [j]) ;
csum += abs_value ;
}
if (csum > anorm)
{
anorm = csum ;
}
}
/* ---------------------------------------------------------------------- */
/* compute estimate of 1-norm of inv (A) */
/* ---------------------------------------------------------------------- */
/* get workspace (size 2*n Entry's) */
X = Numeric->Xwork ; /* size n space used in KLU_solve, tsolve */
X += n ; /* X is size n */
S = X + n ; /* S is size n */
for (i = 0 ; i < n ; i++)
{
CLEAR (S [i]) ;
CLEAR (X [i]) ;
REAL (X [i]) = 1.0 / ((double) n) ;
}
jmax = 0 ;
ainv_norm = 0.0 ;
for (i = 0 ; i < 5 ; i++)
{
if (i > 0)
{
/* X [jmax] is the largest entry in X */
for (j = 0 ; j < n ; j++)
{
/* X [j] = 0 ;*/
CLEAR (X [j]) ;
}
REAL (X [jmax]) = 1 ;
}
KLU_solve (Symbolic, Numeric, n, 1, (double *) X, Common) ;
est_old = ainv_norm ;
ainv_norm = 0.0 ;
for (j = 0 ; j < n ; j++)
{
/* ainv_norm += ABS (X [j]) ;*/
ABS (abs_value, X [j]) ;
ainv_norm += abs_value ;
}
#ifndef COMPLEX
unchanged = TRUE ;
for (j = 0 ; j < n ; j++)
{
double s = (X [j] >= 0) ? 1 : -1 ;
if (s != (Int) REAL (S [j]))
{
S [j] = s ;
unchanged = FALSE ;
}
}
if (i > 0 && (ainv_norm <= est_old || unchanged))
{
break ;
}
#else
for (j = 0 ; j < n ; j++)
{
if (IS_NONZERO (X [j]))
{
ABS (abs_value, X [j]) ;
SCALE_DIV_ASSIGN (S [j], X [j], abs_value) ;
}
else
{
CLEAR (S [j]) ;
REAL (S [j]) = 1 ;
}
}
if (i > 0 && ainv_norm <= est_old)
{
break ;
}
#endif
for (j = 0 ; j < n ; j++)
{
X [j] = S [j] ;
}
#ifndef COMPLEX
/* do a transpose solve */
KLU_tsolve (Symbolic, Numeric, n, 1, X, Common) ;
#else
/* do a conjugate transpose solve */
KLU_tsolve (Symbolic, Numeric, n, 1, (double *) X, 1, Common) ;
#endif
/* jnew = the position of the largest entry in X */
jnew = 0 ;
Xmax = 0 ;
for (j = 0 ; j < n ; j++)
{
/* xj = ABS (X [j]) ;*/
ABS (xj, X [j]) ;
if (xj > Xmax)
{
Xmax = xj ;
jnew = j ;
}
}
if (i > 0 && jnew == jmax)
{
/* the position of the largest entry did not change
* from the previous iteration */
break ;
}
jmax = jnew ;
}
/* ---------------------------------------------------------------------- */
/* compute another estimate of norm(inv(A),1), and take the largest one */
/* ---------------------------------------------------------------------- */
for (j = 0 ; j < n ; j++)
{
CLEAR (X [j]) ;
if (j % 2)
{
REAL (X [j]) = 1 + ((double) j) / ((double) (n-1)) ;
}
else
{
REAL (X [j]) = -1 - ((double) j) / ((double) (n-1)) ;
}
}
KLU_solve (Symbolic, Numeric, n, 1, (double *) X, Common) ;
est_new = 0.0 ;
for (j = 0 ; j < n ; j++)
{
/* est_new += ABS (X [j]) ;*/
ABS (abs_value, X [j]) ;
est_new += abs_value ;
}
est_new = 2 * est_new / (3 * n) ;
ainv_norm = MAX (est_new, ainv_norm) ;
/* ---------------------------------------------------------------------- */
/* compute estimate of condition number */
/* ---------------------------------------------------------------------- */
Common->condest = ainv_norm * anorm ;
return (TRUE) ;
}
/* ========================================================================== */
/* === KLU_flops ============================================================ */
/* ========================================================================== */
/* Compute the flop count for the LU factorization (in Common->flops) */
Int KLU_flops /* return TRUE if successful, FALSE otherwise */
(
KLU_symbolic *Symbolic,
KLU_numeric *Numeric,
KLU_common *Common
)
{
double flops = 0 ;
Int *R, *Ui, *Uip, *Llen, *Ulen ;
Unit **LUbx ;
Unit *LU ;
Int k, ulen, p, n, nk, block, nblocks, k1 ;
/* ---------------------------------------------------------------------- */
/* check inputs */
/* ---------------------------------------------------------------------- */
if (Common == NULL)
{
return (FALSE) ;
}
Common->flops = EMPTY ;
if (Numeric == NULL || Symbolic == NULL)
{
Common->status = KLU_INVALID ;
return (FALSE) ;
}
Common->status = KLU_OK ;
/* ---------------------------------------------------------------------- */
/* get the contents of the Symbolic object */
/* ---------------------------------------------------------------------- */
n = Symbolic->n ;
R = Symbolic->R ;
nblocks = Symbolic->nblocks ;
/* ---------------------------------------------------------------------- */
/* get the contents of the Numeric object */
/* ---------------------------------------------------------------------- */
LUbx = (Unit **) Numeric->LUbx ;
/* ---------------------------------------------------------------------- */
/* compute the flop count */
/* ---------------------------------------------------------------------- */
for (block = 0 ; block < nblocks ; block++)
{
k1 = R [block] ;
nk = R [block+1] - k1 ;
if (nk > 1)
{
Llen = Numeric->Llen + k1 ;
Uip = Numeric->Uip + k1 ;
Ulen = Numeric->Ulen + k1 ;
LU = LUbx [block] ;
for (k = 0 ; k < nk ; k++)
{
/* compute kth column of U, and update kth column of A */
GET_I_POINTER (LU, Uip, Ui, k) ;
ulen = Ulen [k] ;
for (p = 0 ; p < ulen ; p++)
{
flops += 2 * Llen [Ui [p]] ;
}
/* gather and divide by pivot to get kth column of L */
flops += Llen [k] ;
}
}
}
Common->flops = flops ;
return (TRUE) ;
}
/* ========================================================================== */
/* === KLU_rcond ============================================================ */
/* ========================================================================== */
/* Compute a really cheap estimate of the reciprocal of the condition number,
* condition number, min(abs(diag(U))) / max(abs(diag(U))). If U has a zero
* pivot, or a NaN pivot, rcond will be zero. Takes O(n) time.
*/
Int KLU_rcond /* return TRUE if successful, FALSE otherwise */
(
KLU_symbolic *Symbolic, /* input, not modified */
KLU_numeric *Numeric, /* input, not modified */
KLU_common *Common /* result in Common->rcond */
)
{
double ukk, umin = 0, umax = 0 ;
Entry *Udiag ;
Int j, n ;
/* ---------------------------------------------------------------------- */
/* check inputs */
/* ---------------------------------------------------------------------- */
if (Common == NULL)
{
return (FALSE) ;
}
if (Symbolic == NULL)
{
Common->status = KLU_INVALID ;
return (FALSE) ;
}
if (Numeric == NULL)
{
Common->rcond = 0 ;
Common->status = KLU_SINGULAR ;
return (TRUE) ;
}
Common->status = KLU_OK ;
/* ---------------------------------------------------------------------- */
/* compute rcond */
/* ---------------------------------------------------------------------- */
n = Symbolic->n ;
Udiag = Numeric->Udiag ;
for (j = 0 ; j < n ; j++)
{
/* get the magnitude of the pivot */
ABS (ukk, Udiag [j]) ;
if (SCALAR_IS_NAN (ukk) || SCALAR_IS_ZERO (ukk))
{
/* if NaN, or zero, the rcond is zero */
Common->rcond = 0 ;
Common->status = KLU_SINGULAR ;
return (TRUE) ;
}
if (j == 0)
{
/* first pivot entry */
umin = ukk ;
umax = ukk ;
}
else
{
/* subsequent pivots */
umin = MIN (umin, ukk) ;
umax = MAX (umax, ukk) ;
}
}
Common->rcond = umin / umax ;
if (SCALAR_IS_NAN (Common->rcond) || SCALAR_IS_ZERO (Common->rcond))
{
/* this can occur if umin or umax are Inf or NaN */
Common->rcond = 0 ;
Common->status = KLU_SINGULAR ;
}
return (TRUE) ;
}

142
src/maths/KLU/klu_dump.c Normal file
View File

@ -0,0 +1,142 @@
/* ========================================================================== */
/* === KLU_dump ============================================================= */
/* ========================================================================== */
/* Debug routines for klu. Only used when NDEBUG is not defined at
* compile-time.
*/
#include "klu_internal.h"
#ifndef NDEBUG
/* ========================================================================== */
/* === KLU_valid ============================================================ */
/* ========================================================================== */
/* Check if a column-form matrix is valid or not. The matrix A is
* n-by-n. The row indices of entries in column j are in
* Ai [Ap [j] ... Ap [j+1]-1]. Required conditions are:
*
* n >= 0
* nz = Ap [n_col] >= 0 number of entries in the matrix
* Ap [0] == 0
* Ap [j] <= Ap [j+1] for all j in the range 0 to n_col.
* row indices in Ai [Ap [j] ... Ap [j+1]-1]
* must be in the range 0 to n_row-1,
* and no duplicate entries can exist (duplicates not checked here).
*
* Not user-callable. Only used when debugging.
*/
Int KLU_valid (Int n, Int Ap [ ], Int Ai [ ], Entry Ax [ ])
{
Int nz, j, p1, p2, i, p ;
PRINTF (("\ncolumn oriented matrix, n = %d\n", n)) ;
if (n <= 0)
{
PRINTF (("n must be >= 0: %d\n", n)) ;
return (FALSE) ;
}
nz = Ap [n] ;
if (Ap [0] != 0 || nz < 0)
{
/* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */
PRINTF (("column 0 pointer bad or nz < 0\n")) ;
return (FALSE) ;
}
for (j = 0 ; j < n ; j++)
{
p1 = Ap [j] ;
p2 = Ap [j+1] ;
PRINTF (("\nColumn: %d p1: %d p2: %d\n", j, p1, p2)) ;
if (p1 > p2)
{
/* column pointers must be ascending */
PRINTF (("column %d pointer bad\n", j)) ;
return (FALSE) ;
}
for (p = p1 ; p < p2 ; p++)
{
i = Ai [p] ;
PRINTF (("row: %d", i)) ;
if (i < 0 || i >= n)
{
/* row index out of range */
PRINTF (("index out of range, col %d row %d\n", j, i)) ;
return (FALSE) ;
}
if (Ax != (Entry *) NULL)
{
PRINT_ENTRY (Ax [p]) ;
}
PRINTF (("\n")) ;
}
}
return (TRUE) ;
}
/* ========================================================================== */
/* === KLU_valid_LU ========================================================= */
/* ========================================================================== */
/* This function does the same validity tests as KLU_valid but for the
* LU factor storage format. The flag flag_test_start_ptr is used to
* test if Xip [0] = 0. This is not applicable for U. So when calling this
* function for U, the flag should be set to false. Only used when debugging.
*/
Int KLU_valid_LU (Int n, Int flag_test_start_ptr, Int Xip [ ],
Int Xlen [ ], Unit LU [ ])
{
Int *Xi ;
Entry *Xx ;
Int j, p1, p2, i, p, len ;
PRINTF (("\ncolumn oriented matrix, n = %d\n", n)) ;
if (n <= 0)
{
PRINTF (("n must be >= 0: %d\n", n)) ;
return (FALSE) ;
}
if (flag_test_start_ptr && Xip [0] != 0)
{
/* column pointers must start at Xip [0] = 0*/
PRINTF (("column 0 pointer bad\n")) ;
return (FALSE) ;
}
for (j = 0 ; j < n ; j++)
{
p1 = Xip [j] ;
p2 = Xip [j+1] ;
PRINTF (("\nColumn: %d p1: %d p2: %d\n", j, p1, p2)) ;
if (p1 > p2)
{
/* column pointers must be ascending */
PRINTF (("column %d pointer bad\n", j)) ;
return (FALSE) ;
}
GET_POINTER (LU, Xip, Xlen, Xi, Xx, j, len) ;
for (p = 0 ; p < len ; p++)
{
i = Xi [p] ;
PRINTF (("row: %d", i)) ;
if (i < 0 || i >= n)
{
/* row index out of range */
PRINTF (("index out of range, col %d row %d\n", j, i)) ;
return (FALSE) ;
}
if (Xx != (Entry *) NULL)
{
PRINT_ENTRY (Xx [p]) ;
}
PRINTF (("\n")) ;
}
}
return (TRUE) ;
}
#endif

290
src/maths/KLU/klu_extract.c Normal file
View File

@ -0,0 +1,290 @@
/* ========================================================================== */
/* === KLU_extract ========================================================== */
/* ========================================================================== */
/* Extract KLU factorization into conventional compressed-column matrices.
* If any output array is NULL, that part of the LU factorization is not
* extracted (this is not an error condition).
*
* nnz(L) = Numeric->lnz, nnz(U) = Numeric->unz, and nnz(F) = Numeric->Offp [n]
*/
#include "klu_internal.h"
Int KLU_extract /* returns TRUE if successful, FALSE otherwise */
(
/* inputs: */
KLU_numeric *Numeric,
KLU_symbolic *Symbolic,
/* outputs, all of which must be allocated on input */
/* L */
Int *Lp, /* size n+1 */
Int *Li, /* size nnz(L) */
double *Lx, /* size nnz(L) */
#ifdef COMPLEX
double *Lz, /* size nnz(L) for the complex case, ignored if real */
#endif
/* U */
Int *Up, /* size n+1 */
Int *Ui, /* size nnz(U) */
double *Ux, /* size nnz(U) */
#ifdef COMPLEX
double *Uz, /* size nnz(U) for the complex case, ignored if real */
#endif
/* F */
Int *Fp, /* size n+1 */
Int *Fi, /* size nnz(F) */
double *Fx, /* size nnz(F) */
#ifdef COMPLEX
double *Fz, /* size nnz(F) for the complex case, ignored if real */
#endif
/* P, row permutation */
Int *P, /* size n */
/* Q, column permutation */
Int *Q, /* size n */
/* Rs, scale factors */
double *Rs, /* size n */
/* R, block boundaries */
Int *R, /* size nblocks+1 */
KLU_common *Common
)
{
Int *Lip, *Llen, *Uip, *Ulen, *Li2, *Ui2 ;
Unit *LU ;
Entry *Lx2, *Ux2, *Ukk ;
Int i, k, block, nblocks, n, nz, k1, k2, nk, len, kk, p ;
if (Common == NULL)
{
return (FALSE) ;
}
if (Symbolic == NULL || Numeric == NULL)
{
Common->status = KLU_INVALID ;
return (FALSE) ;
}
Common->status = KLU_OK ;
n = Symbolic->n ;
nblocks = Symbolic->nblocks ;
/* ---------------------------------------------------------------------- */
/* extract scale factors */
/* ---------------------------------------------------------------------- */
if (Rs != NULL)
{
if (Numeric->Rs != NULL)
{
for (i = 0 ; i < n ; i++)
{
Rs [i] = Numeric->Rs [i] ;
}
}
else
{
/* no scaling */
for (i = 0 ; i < n ; i++)
{
Rs [i] = 1 ;
}
}
}
/* ---------------------------------------------------------------------- */
/* extract block boundaries */
/* ---------------------------------------------------------------------- */
if (R != NULL)
{
for (block = 0 ; block <= nblocks ; block++)
{
R [block] = Symbolic->R [block] ;
}
}
/* ---------------------------------------------------------------------- */
/* extract final row permutation */
/* ---------------------------------------------------------------------- */
if (P != NULL)
{
for (k = 0 ; k < n ; k++)
{
P [k] = Numeric->Pnum [k] ;
}
}
/* ---------------------------------------------------------------------- */
/* extract column permutation */
/* ---------------------------------------------------------------------- */
if (Q != NULL)
{
for (k = 0 ; k < n ; k++)
{
Q [k] = Symbolic->Q [k] ;
}
}
/* ---------------------------------------------------------------------- */
/* extract each block of L */
/* ---------------------------------------------------------------------- */
if (Lp != NULL && Li != NULL && Lx != NULL
#ifdef COMPLEX
&& Lz != NULL
#endif
)
{
nz = 0 ;
for (block = 0 ; block < nblocks ; block++)
{
k1 = Symbolic->R [block] ;
k2 = Symbolic->R [block+1] ;
nk = k2 - k1 ;
if (nk == 1)
{
/* singleton block */
Lp [k1] = nz ;
Li [nz] = k1 ;
Lx [nz] = 1 ;
#ifdef COMPLEX
Lz [nz] = 0 ;
#endif
nz++ ;
}
else
{
/* non-singleton block */
LU = Numeric->LUbx [block] ;
Lip = Numeric->Lip + k1 ;
Llen = Numeric->Llen + k1 ;
for (kk = 0 ; kk < nk ; kk++)
{
Lp [k1+kk] = nz ;
/* add the unit diagonal entry */
Li [nz] = k1 + kk ;
Lx [nz] = 1 ;
#ifdef COMPLEX
Lz [nz] = 0 ;
#endif
nz++ ;
GET_POINTER (LU, Lip, Llen, Li2, Lx2, kk, len) ;
for (p = 0 ; p < len ; p++)
{
Li [nz] = k1 + Li2 [p] ;
Lx [nz] = REAL (Lx2 [p]) ;
#ifdef COMPLEX
Lz [nz] = IMAG (Lx2 [p]) ;
#endif
nz++ ;
}
}
}
}
Lp [n] = nz ;
ASSERT (nz == Numeric->lnz) ;
}
/* ---------------------------------------------------------------------- */
/* extract each block of U */
/* ---------------------------------------------------------------------- */
if (Up != NULL && Ui != NULL && Ux != NULL
#ifdef COMPLEX
&& Uz != NULL
#endif
)
{
nz = 0 ;
for (block = 0 ; block < nblocks ; block++)
{
k1 = Symbolic->R [block] ;
k2 = Symbolic->R [block+1] ;
nk = k2 - k1 ;
Ukk = ((Entry *) Numeric->Udiag) + k1 ;
if (nk == 1)
{
/* singleton block */
Up [k1] = nz ;
Ui [nz] = k1 ;
Ux [nz] = REAL (Ukk [0]) ;
#ifdef COMPLEX
Uz [nz] = IMAG (Ukk [0]) ;
#endif
nz++ ;
}
else
{
/* non-singleton block */
LU = Numeric->LUbx [block] ;
Uip = Numeric->Uip + k1 ;
Ulen = Numeric->Ulen + k1 ;
for (kk = 0 ; kk < nk ; kk++)
{
Up [k1+kk] = nz ;
GET_POINTER (LU, Uip, Ulen, Ui2, Ux2, kk, len) ;
for (p = 0 ; p < len ; p++)
{
Ui [nz] = k1 + Ui2 [p] ;
Ux [nz] = REAL (Ux2 [p]) ;
#ifdef COMPLEX
Uz [nz] = IMAG (Ux2 [p]) ;
#endif
nz++ ;
}
/* add the diagonal entry */
Ui [nz] = k1 + kk ;
Ux [nz] = REAL (Ukk [kk]) ;
#ifdef COMPLEX
Uz [nz] = IMAG (Ukk [kk]) ;
#endif
nz++ ;
}
}
}
Up [n] = nz ;
ASSERT (nz == Numeric->unz) ;
}
/* ---------------------------------------------------------------------- */
/* extract the off-diagonal blocks, F */
/* ---------------------------------------------------------------------- */
if (Fp != NULL && Fi != NULL && Fx != NULL
#ifdef COMPLEX
&& Fz != NULL
#endif
)
{
for (k = 0 ; k <= n ; k++)
{
Fp [k] = Numeric->Offp [k] ;
}
nz = Fp [n] ;
for (k = 0 ; k < nz ; k++)
{
Fi [k] = Numeric->Offi [k] ;
}
for (k = 0 ; k < nz ; k++)
{
Fx [k] = REAL (((Entry *) Numeric->Offx) [k]) ;
#ifdef COMPLEX
Fz [k] = IMAG (((Entry *) Numeric->Offx) [k]) ;
#endif
}
}
return (TRUE) ;
}

545
src/maths/KLU/klu_factor.c Normal file
View File

@ -0,0 +1,545 @@
/* ========================================================================== */
/* === KLU_factor =========================================================== */
/* ========================================================================== */
/* Factor the matrix, after ordering and analyzing it with KLU_analyze
* or KLU_analyze_given.
*/
#include "klu_internal.h"
/* ========================================================================== */
/* === KLU_factor2 ========================================================== */
/* ========================================================================== */
static void factor2
(
/* inputs, not modified */
Int Ap [ ], /* size n+1, column pointers */
Int Ai [ ], /* size nz, row indices */
Entry Ax [ ],
KLU_symbolic *Symbolic,
/* inputs, modified on output: */
KLU_numeric *Numeric,
KLU_common *Common
)
{
double lsize ;
double *Lnz, *Rs ;
Int *P, *Q, *R, *Pnum, *Offp, *Offi, *Pblock, *Pinv, *Iwork,
*Lip, *Uip, *Llen, *Ulen ;
Entry *Offx, *X, s, *Udiag ;
Unit **LUbx ;
Int k1, k2, nk, k, block, oldcol, pend, oldrow, n, lnz, unz, p, newrow,
nblocks, poff, nzoff, lnz_block, unz_block, scale, max_lnz_block,
max_unz_block ;
/* ---------------------------------------------------------------------- */
/* initializations */
/* ---------------------------------------------------------------------- */
/* get the contents of the Symbolic object */
n = Symbolic->n ;
P = Symbolic->P ;
Q = Symbolic->Q ;
R = Symbolic->R ;
Lnz = Symbolic->Lnz ;
nblocks = Symbolic->nblocks ;
nzoff = Symbolic->nzoff ;
Pnum = Numeric->Pnum ;
Offp = Numeric->Offp ;
Offi = Numeric->Offi ;
Offx = (Entry *) Numeric->Offx ;
Lip = Numeric->Lip ;
Uip = Numeric->Uip ;
Llen = Numeric->Llen ;
Ulen = Numeric->Ulen ;
LUbx = (Unit **) Numeric->LUbx ;
Udiag = Numeric->Udiag ;
Rs = Numeric->Rs ;
Pinv = Numeric->Pinv ;
X = (Entry *) Numeric->Xwork ; /* X is of size n */
Iwork = Numeric->Iwork ; /* 5*maxblock for KLU_factor */
/* 1*maxblock for Pblock */
Pblock = Iwork + 5*((size_t) Symbolic->maxblock) ;
Common->nrealloc = 0 ;
scale = Common->scale ;
max_lnz_block = 1 ;
max_unz_block = 1 ;
/* compute the inverse of P from symbolic analysis. Will be updated to
* become the inverse of the numerical factorization when the factorization
* is done, for use in KLU_refactor */
#ifndef NDEBUG
for (k = 0 ; k < n ; k++)
{
Pinv [k] = EMPTY ;
}
#endif
for (k = 0 ; k < n ; k++)
{
ASSERT (P [k] >= 0 && P [k] < n) ;
Pinv [P [k]] = k ;
}
#ifndef NDEBUG
for (k = 0 ; k < n ; k++) ASSERT (Pinv [k] != EMPTY) ;
#endif
lnz = 0 ;
unz = 0 ;
Common->noffdiag = 0 ;
Offp [0] = 0 ;
/* ---------------------------------------------------------------------- */
/* optionally check input matrix and compute scale factors */
/* ---------------------------------------------------------------------- */
if (scale >= 0)
{
/* use Pnum as workspace. NOTE: scale factors are not yet permuted
* according to the final pivot row ordering, so Rs [oldrow] is the
* scale factor for A (oldrow,:), for the user's matrix A. Pnum is
* used as workspace in KLU_scale. When the factorization is done,
* the scale factors are permuted according to the final pivot row
* permutation, so that Rs [k] is the scale factor for the kth row of
* A(p,q) where p and q are the final row and column permutations. */
KLU_scale (scale, n, Ap, Ai, (double *) Ax, Rs, Pnum, Common) ;
if (Common->status < KLU_OK)
{
/* matrix is invalid */
return ;
}
}
#ifndef NDEBUG
if (scale > 0)
{
for (k = 0 ; k < n ; k++) PRINTF (("Rs [%d] %g\n", k, Rs [k])) ;
}
#endif
/* ---------------------------------------------------------------------- */
/* factor each block using klu */
/* ---------------------------------------------------------------------- */
for (block = 0 ; block < nblocks ; block++)
{
/* ------------------------------------------------------------------ */
/* the block is from rows/columns k1 to k2-1 */
/* ------------------------------------------------------------------ */
k1 = R [block] ;
k2 = R [block+1] ;
nk = k2 - k1 ;
PRINTF (("FACTOR BLOCK %d, k1 %d k2-1 %d nk %d\n", block, k1,k2-1,nk)) ;
if (nk == 1)
{
/* -------------------------------------------------------------- */
/* singleton case */
/* -------------------------------------------------------------- */
poff = Offp [k1] ;
oldcol = Q [k1] ;
pend = Ap [oldcol+1] ;
CLEAR (s) ;
if (scale <= 0)
{
/* no scaling */
for (p = Ap [oldcol] ; p < pend ; p++)
{
oldrow = Ai [p] ;
newrow = Pinv [oldrow] ;
if (newrow < k1)
{
Offi [poff] = oldrow ;
Offx [poff] = Ax [p] ;
poff++ ;
}
else
{
ASSERT (newrow == k1) ;
PRINTF (("singleton block %d", block)) ;
PRINT_ENTRY (Ax [p]) ;
s = Ax [p] ;
}
}
}
else
{
/* row scaling. NOTE: scale factors are not yet permuted
* according to the pivot row permutation, so Rs [oldrow] is
* used below. When the factorization is done, the scale
* factors are permuted, so that Rs [newrow] will be used in
* klu_solve, klu_tsolve, and klu_rgrowth */
for (p = Ap [oldcol] ; p < pend ; p++)
{
oldrow = Ai [p] ;
newrow = Pinv [oldrow] ;
if (newrow < k1)
{
Offi [poff] = oldrow ;
/* Offx [poff] = Ax [p] / Rs [oldrow] ; */
SCALE_DIV_ASSIGN (Offx [poff], Ax [p], Rs [oldrow]) ;
poff++ ;
}
else
{
ASSERT (newrow == k1) ;
PRINTF (("singleton block %d ", block)) ;
PRINT_ENTRY (Ax[p]) ;
SCALE_DIV_ASSIGN (s, Ax [p], Rs [oldrow]) ;
}
}
}
Udiag [k1] = s ;
if (IS_ZERO (s))
{
/* singular singleton */
Common->status = KLU_SINGULAR ;
Common->numerical_rank = k1 ;
Common->singular_col = oldcol ;
if (Common->halt_if_singular)
{
return ;
}
}
Offp [k1+1] = poff ;
Pnum [k1] = P [k1] ;
lnz++ ;
unz++ ;
}
else
{
/* -------------------------------------------------------------- */
/* construct and factorize the kth block */
/* -------------------------------------------------------------- */
if (Lnz [block] < 0)
{
/* COLAMD was used - no estimate of fill-in */
/* use 10 times the nnz in A, plus n */
lsize = -(Common->initmem) ;
}
else
{
lsize = Common->initmem_amd * Lnz [block] + nk ;
}
/* allocates 1 arrays: LUbx [block] */
Numeric->LUsize [block] = KLU_kernel_factor (nk, Ap, Ai, Ax, Q,
lsize, &LUbx [block], Udiag + k1, Llen + k1, Ulen + k1,
Lip + k1, Uip + k1, Pblock, &lnz_block, &unz_block,
X, Iwork, k1, Pinv, Rs, Offp, Offi, Offx, Common) ;
if (Common->status < KLU_OK ||
(Common->status == KLU_SINGULAR && Common->halt_if_singular))
{
/* out of memory, invalid inputs, or singular */
return ;
}
PRINTF (("\n----------------------- L %d:\n", block)) ;
ASSERT (KLU_valid_LU (nk, TRUE, Lip+k1, Llen+k1, LUbx [block])) ;
PRINTF (("\n----------------------- U %d:\n", block)) ;
ASSERT (KLU_valid_LU (nk, FALSE, Uip+k1, Ulen+k1, LUbx [block])) ;
/* -------------------------------------------------------------- */
/* get statistics */
/* -------------------------------------------------------------- */
lnz += lnz_block ;
unz += unz_block ;
max_lnz_block = MAX (max_lnz_block, lnz_block) ;
max_unz_block = MAX (max_unz_block, unz_block) ;
if (Lnz [block] == EMPTY)
{
/* revise estimate for subsequent factorization */
Lnz [block] = MAX (lnz_block, unz_block) ;
}
/* -------------------------------------------------------------- */
/* combine the klu row ordering with the symbolic pre-ordering */
/* -------------------------------------------------------------- */
PRINTF (("Pnum, 1-based:\n")) ;
for (k = 0 ; k < nk ; k++)
{
ASSERT (k + k1 < n) ;
ASSERT (Pblock [k] + k1 < n) ;
Pnum [k + k1] = P [Pblock [k] + k1] ;
PRINTF (("Pnum (%d + %d + 1 = %d) = %d + 1 = %d\n",
k, k1, k+k1+1, Pnum [k+k1], Pnum [k+k1]+1)) ;
}
/* the local pivot row permutation Pblock is no longer needed */
}
}
ASSERT (nzoff == Offp [n]) ;
PRINTF (("\n------------------- Off diagonal entries:\n")) ;
ASSERT (KLU_valid (n, Offp, Offi, Offx)) ;
Numeric->lnz = lnz ;
Numeric->unz = unz ;
Numeric->max_lnz_block = max_lnz_block ;
Numeric->max_unz_block = max_unz_block ;
/* compute the inverse of Pnum */
#ifndef NDEBUG
for (k = 0 ; k < n ; k++)
{
Pinv [k] = EMPTY ;
}
#endif
for (k = 0 ; k < n ; k++)
{
ASSERT (Pnum [k] >= 0 && Pnum [k] < n) ;
Pinv [Pnum [k]] = k ;
}
#ifndef NDEBUG
for (k = 0 ; k < n ; k++) ASSERT (Pinv [k] != EMPTY) ;
#endif
/* permute scale factors Rs according to pivotal row order */
if (scale > 0)
{
for (k = 0 ; k < n ; k++)
{
REAL (X [k]) = Rs [Pnum [k]] ;
}
for (k = 0 ; k < n ; k++)
{
Rs [k] = REAL (X [k]) ;
}
}
PRINTF (("\n------------------- Off diagonal entries, old:\n")) ;
ASSERT (KLU_valid (n, Offp, Offi, Offx)) ;
/* apply the pivot row permutations to the off-diagonal entries */
for (p = 0 ; p < nzoff ; p++)
{
ASSERT (Offi [p] >= 0 && Offi [p] < n) ;
Offi [p] = Pinv [Offi [p]] ;
}
PRINTF (("\n------------------- Off diagonal entries, new:\n")) ;
ASSERT (KLU_valid (n, Offp, Offi, Offx)) ;
#ifndef NDEBUG
{
PRINTF (("\n ############# KLU_BTF_FACTOR done, nblocks %d\n",nblocks));
Entry ss, *Udiag = Numeric->Udiag ;
for (block = 0 ; block < nblocks && Common->status == KLU_OK ; block++)
{
k1 = R [block] ;
k2 = R [block+1] ;
nk = k2 - k1 ;
PRINTF (("\n======================KLU_factor output: k1 %d k2 %d nk %d\n",k1,k2,nk)) ;
if (nk == 1)
{
PRINTF (("singleton ")) ;
/* ENTRY_PRINT (singleton [block]) ; */
ss = Udiag [k1] ;
PRINT_ENTRY (ss) ;
}
else
{
Int *Lip, *Uip, *Llen, *Ulen ;
Unit *LU ;
Lip = Numeric->Lip + k1 ;
Llen = Numeric->Llen + k1 ;
LU = (Unit *) Numeric->LUbx [block] ;
PRINTF (("\n---- L block %d\n", block));
ASSERT (KLU_valid_LU (nk, TRUE, Lip, Llen, LU)) ;
Uip = Numeric->Uip + k1 ;
Ulen = Numeric->Ulen + k1 ;
PRINTF (("\n---- U block %d\n", block)) ;
ASSERT (KLU_valid_LU (nk, FALSE, Uip, Ulen, LU)) ;
}
}
}
#endif
}
/* ========================================================================== */
/* === KLU_factor =========================================================== */
/* ========================================================================== */
KLU_numeric *KLU_factor /* returns NULL if error, or a valid
KLU_numeric object if successful */
(
/* --- inputs --- */
Int Ap [ ], /* size n+1, column pointers */
Int Ai [ ], /* size nz, row indices */
double Ax [ ],
KLU_symbolic *Symbolic,
/* -------------- */
KLU_common *Common
)
{
Int n, nzoff, nblocks, maxblock, k, ok = TRUE ;
Int *R ;
KLU_numeric *Numeric ;
size_t n1, nzoff1, s, b6, n3 ;
if (Common == NULL)
{
return (NULL) ;
}
Common->status = KLU_OK ;
Common->numerical_rank = EMPTY ;
Common->singular_col = EMPTY ;
/* ---------------------------------------------------------------------- */
/* get the contents of the Symbolic object */
/* ---------------------------------------------------------------------- */
/* check for a valid Symbolic object */
if (Symbolic == NULL)
{
Common->status = KLU_INVALID ;
return (NULL) ;
}
n = Symbolic->n ;
nzoff = Symbolic->nzoff ;
nblocks = Symbolic->nblocks ;
maxblock = Symbolic->maxblock ;
R = Symbolic->R ;
PRINTF (("KLU_factor: n %d nzoff %d nblocks %d maxblock %d\n",
n, nzoff, nblocks, maxblock)) ;
/* ---------------------------------------------------------------------- */
/* get control parameters and make sure they are in the proper range */
/* ---------------------------------------------------------------------- */
Common->initmem_amd = MAX (1.0, Common->initmem_amd) ;
Common->initmem = MAX (1.0, Common->initmem) ;
Common->tol = MIN (Common->tol, 1.0) ;
Common->tol = MAX (0.0, Common->tol) ;
Common->memgrow = MAX (1.0, Common->memgrow) ;
/* ---------------------------------------------------------------------- */
/* allocate the Numeric object */
/* ---------------------------------------------------------------------- */
/* this will not cause size_t overflow (already checked by KLU_symbolic) */
n1 = ((size_t) n) + 1 ;
nzoff1 = ((size_t) nzoff) + 1 ;
Numeric = KLU_malloc (sizeof (KLU_numeric), 1, Common) ;
if (Common->status < KLU_OK)
{
/* out of memory */
Common->status = KLU_OUT_OF_MEMORY ;
return (NULL) ;
}
Numeric->n = n ;
Numeric->nblocks = nblocks ;
Numeric->nzoff = nzoff ;
Numeric->Pnum = KLU_malloc (n, sizeof (Int), Common) ;
Numeric->Offp = KLU_malloc (n1, sizeof (Int), Common) ;
Numeric->Offi = KLU_malloc (nzoff1, sizeof (Int), Common) ;
Numeric->Offx = KLU_malloc (nzoff1, sizeof (Entry), Common) ;
Numeric->Lip = KLU_malloc (n, sizeof (Int), Common) ;
Numeric->Uip = KLU_malloc (n, sizeof (Int), Common) ;
Numeric->Llen = KLU_malloc (n, sizeof (Int), Common) ;
Numeric->Ulen = KLU_malloc (n, sizeof (Int), Common) ;
Numeric->LUsize = KLU_malloc (nblocks, sizeof (size_t), Common) ;
Numeric->LUbx = KLU_malloc (nblocks, sizeof (Unit *), Common) ;
if (Numeric->LUbx != NULL)
{
for (k = 0 ; k < nblocks ; k++)
{
Numeric->LUbx [k] = NULL ;
}
}
Numeric->Udiag = KLU_malloc (n, sizeof (Entry), Common) ;
if (Common->scale > 0)
{
Numeric->Rs = KLU_malloc (n, sizeof (double), Common) ;
}
else
{
/* no scaling */
Numeric->Rs = NULL ;
}
Numeric->Pinv = KLU_malloc (n, sizeof (Int), Common) ;
/* allocate permanent workspace for factorization and solve. Note that the
* solver will use an Xwork of size 4n, whereas the factorization codes use
* an Xwork of size n and integer space (Iwork) of size 6n. KLU_condest
* uses an Xwork of size 2n. Total size is:
*
* n*sizeof(Entry) + max (6*maxblock*sizeof(Int), 3*n*sizeof(Entry))
*/
s = KLU_mult_size_t (n, sizeof (Entry), &ok) ;
n3 = KLU_mult_size_t (n, 3 * sizeof (Entry), &ok) ;
b6 = KLU_mult_size_t (maxblock, 6 * sizeof (Int), &ok) ;
Numeric->worksize = KLU_add_size_t (s, MAX (n3, b6), &ok) ;
Numeric->Work = KLU_malloc (Numeric->worksize, 1, Common) ;
Numeric->Xwork = Numeric->Work ;
Numeric->Iwork = (Int *) ((Entry *) Numeric->Xwork + n) ;
if (!ok || Common->status < KLU_OK)
{
/* out of memory or problem too large */
Common->status = ok ? KLU_OUT_OF_MEMORY : KLU_TOO_LARGE ;
KLU_free_numeric (&Numeric, Common) ;
return (NULL) ;
}
/* ---------------------------------------------------------------------- */
/* factorize the blocks */
/* ---------------------------------------------------------------------- */
factor2 (Ap, Ai, (Entry *) Ax, Symbolic, Numeric, Common) ;
/* ---------------------------------------------------------------------- */
/* return or free the Numeric object */
/* ---------------------------------------------------------------------- */
if (Common->status < KLU_OK)
{
/* out of memory or inputs invalid */
KLU_free_numeric (&Numeric, Common) ;
}
else if (Common->status == KLU_SINGULAR)
{
if (Common->halt_if_singular)
{
/* Matrix is singular, and the Numeric object is only partially
* defined because we halted early. This is the default case for
* a singular matrix. */
KLU_free_numeric (&Numeric, Common) ;
}
}
else if (Common->status == KLU_OK)
{
/* successful non-singular factorization */
Common->numerical_rank = n ;
Common->singular_col = n ;
}
return (Numeric) ;
}

View File

@ -0,0 +1,71 @@
/* ========================================================================== */
/* === KLU_free_numeric ===================================================== */
/* ========================================================================== */
/* Free the KLU Numeric object. */
#include "klu_internal.h"
Int KLU_free_numeric
(
KLU_numeric **NumericHandle,
KLU_common *Common
)
{
KLU_numeric *Numeric ;
Unit **LUbx ;
size_t *LUsize ;
Int block, n, nzoff, nblocks ;
if (Common == NULL)
{
return (FALSE) ;
}
if (NumericHandle == NULL || *NumericHandle == NULL)
{
return (TRUE) ;
}
Numeric = *NumericHandle ;
n = Numeric->n ;
nzoff = Numeric->nzoff ;
nblocks = Numeric->nblocks ;
LUsize = Numeric->LUsize ;
LUbx = (Unit **) Numeric->LUbx ;
if (LUbx != NULL)
{
for (block = 0 ; block < nblocks ; block++)
{
KLU_free (LUbx [block], LUsize ? LUsize [block] : 0,
sizeof (Unit), Common) ;
}
}
KLU_free (Numeric->Pnum, n, sizeof (Int), Common) ;
KLU_free (Numeric->Offp, n+1, sizeof (Int), Common) ;
KLU_free (Numeric->Offi, nzoff+1, sizeof (Int), Common) ;
KLU_free (Numeric->Offx, nzoff+1, sizeof (Entry), Common) ;
KLU_free (Numeric->Lip, n, sizeof (Int), Common) ;
KLU_free (Numeric->Llen, n, sizeof (Int), Common) ;
KLU_free (Numeric->Uip, n, sizeof (Int), Common) ;
KLU_free (Numeric->Ulen, n, sizeof (Int), Common) ;
KLU_free (Numeric->LUsize, nblocks, sizeof (size_t), Common) ;
KLU_free (Numeric->LUbx, nblocks, sizeof (Unit *), Common) ;
KLU_free (Numeric->Udiag, n, sizeof (Entry), Common) ;
KLU_free (Numeric->Rs, n, sizeof (double), Common) ;
KLU_free (Numeric->Pinv, n, sizeof (Int), Common) ;
KLU_free (Numeric->Work, Numeric->worksize, 1, Common) ;
KLU_free (Numeric, 1, sizeof (KLU_numeric), Common) ;
*NumericHandle = NULL ;
return (TRUE) ;
}

View File

@ -0,0 +1,34 @@
/* ========================================================================== */
/* === KLU_free_symbolic ==================================================== */
/* ========================================================================== */
/* Free the KLU Symbolic object. */
#include "klu_internal.h"
Int KLU_free_symbolic
(
KLU_symbolic **SymbolicHandle,
KLU_common *Common
)
{
KLU_symbolic *Symbolic ;
Int n ;
if (Common == NULL)
{
return (FALSE) ;
}
if (SymbolicHandle == NULL || *SymbolicHandle == NULL)
{
return (TRUE) ;
}
Symbolic = *SymbolicHandle ;
n = Symbolic->n ;
KLU_free (Symbolic->P, n, sizeof (Int), Common) ;
KLU_free (Symbolic->Q, n, sizeof (Int), Common) ;
KLU_free (Symbolic->R, n+1, sizeof (Int), Common) ;
KLU_free (Symbolic->Lnz, n, sizeof (double), Common) ;
KLU_free (Symbolic, 1, sizeof (KLU_symbolic), Common) ;
*SymbolicHandle = NULL ;
return (TRUE) ;
}

View File

@ -0,0 +1,243 @@
/* ========================================================================== */
/* === KLU/Include/klu_internal.h =========================================== */
/* ========================================================================== */
/* For internal use in KLU routines only, not for user programs */
#ifndef _KLU_INTERNAL_H
#define _KLU_INTERNAL_H
#include "ngspice/klu.h"
#include "ngspice/btf.h"
#include "klu_version.h"
/* ========================================================================== */
/* make sure debugging and printing is turned off */
#ifndef NDEBUG
#define NDEBUG
#endif
#ifndef NPRINT
#define NPRINT
#endif
/* To enable debugging and assertions, uncomment this line:
#undef NDEBUG
*/
/* To enable diagnostic printing, uncomment this line:
#undef NPRINT
*/
/* ========================================================================== */
#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <math.h>
#undef ASSERT
#ifndef NDEBUG
#define ASSERT(a) assert(a)
#else
#define ASSERT(a)
#endif
#define SCALAR_IS_NAN(x) ((x) != (x))
/* true if an integer (stored in double x) would overflow (or if x is NaN) */
#define INT_OVERFLOW(x) ((!((x) * (1.0+1e-8) <= (double) INT_MAX)) \
|| SCALAR_IS_NAN (x))
#undef TRUE
#undef FALSE
#undef MAX
#undef MIN
#undef PRINTF
#undef FLIP
#ifndef NPRINT
#define PRINTF(s) { printf s ; } ;
#else
#define PRINTF(s)
#endif
#define TRUE 1
#define FALSE 0
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
/* FLIP is a "negation about -1", and is used to mark an integer i that is
* normally non-negative. FLIP (EMPTY) is EMPTY. FLIP of a number > EMPTY
* is negative, and FLIP of a number < EMTPY is positive. FLIP (FLIP (i)) = i
* for all integers i. UNFLIP (i) is >= EMPTY. */
#define EMPTY (-1)
#define FLIP(i) (-(i)-2)
#define UNFLIP(i) (((i) < EMPTY) ? FLIP (i) : (i))
size_t KLU_kernel /* final size of LU on output */
(
/* input, not modified */
Int n, /* A is n-by-n */
Int Ap [ ], /* size n+1, column pointers for A */
Int Ai [ ], /* size nz = Ap [n], row indices for A */
Entry Ax [ ], /* size nz, values of A */
Int Q [ ], /* size n, optional input permutation */
size_t lusize, /* initial size of LU */
/* output, not defined on input */
Int Pinv [ ], /* size n */
Int P [ ], /* size n */
Unit **p_LU, /* size lusize on input, size Uxp[n] on output*/
Entry Udiag [ ], /* size n, diagonal of U */
Int Llen [ ], /* size n, column length of L */
Int Ulen [ ], /* size n, column length of U */
Int Lip [ ], /* size n+1 */
Int Uip [ ], /* size n+1 */
Int *lnz, /* size of L */
Int *unz, /* size of U */
/* workspace, not defined on input */
Entry X [ ], /* size n, zero on output */
/* workspace, not defined on input or output */
Int Stack [ ], /* size n */
Int Flag [ ], /* size n */
Int adj_pos [ ], /* size n */
/* workspace for pruning only */
Int Lpend [ ], /* size n workspace */
/* inputs, not modified on output */
Int k1, /* the block of A is from k1 to k2-1 */
Int PSinv [ ], /* inverse of P from symbolic factorization */
double Rs [ ], /* scale factors for A */
/* inputs, modified on output */
Int Offp [ ], /* off-diagonal matrix (modified by this routine) */
Int Offi [ ],
Entry Offx [ ],
KLU_common *Common /* the control input/output structure */
) ;
size_t KLU_kernel_factor /* 0 if failure, size of LU if OK */
(
/* inputs, not modified */
Int n, /* A is n-by-n. n must be > 0. */
Int Ap [ ], /* size n+1, column pointers for A */
Int Ai [ ], /* size nz = Ap [n], row indices for A */
Entry Ax [ ], /* size nz, values of A */
Int Q [ ], /* size n, optional column permutation */
double Lsize, /* initial size of L and U */
/* outputs, not defined on input */
Unit **p_LU, /* row indices and values of L and U */
Entry Udiag [ ], /* size n, diagonal of U */
Int Llen [ ], /* size n, column length of L */
Int Ulen [ ], /* size n, column length of U */
Int Lip [ ], /* size n+1, column pointers of L */
Int Uip [ ], /* size n+1, column pointers of U */
Int P [ ], /* row permutation, size n */
Int *lnz, /* size of L */
Int *unz, /* size of U */
/* workspace, undefined on input */
Entry *X, /* size n entries. Zero on output */
Int *Work, /* size 5n Int's */
/* inputs, not modified on output */
Int k1, /* the block of A is from k1 to k2-1 */
Int PSinv [ ], /* inverse of P from symbolic factorization */
double Rs [ ], /* scale factors for A */
/* inputs, modified on output */
Int Offp [ ], /* off-diagonal matrix (modified by this routine) */
Int Offi [ ],
Entry Offx [ ],
KLU_common *Common /* the control input/output structure */
) ;
void KLU_lsolve
(
/* inputs, not modified: */
Int n,
Int Lp [ ],
Int Li [ ],
Unit LU [ ],
Int nrhs,
/* right-hand-side on input, solution to Lx=b on output */
Entry X [ ]
) ;
void KLU_ltsolve
(
/* inputs, not modified: */
Int n,
Int Lp [ ],
Int Li [ ],
Unit LU [ ],
Int nrhs,
#ifdef COMPLEX
Int conj_solve,
#endif
/* right-hand-side on input, solution to L'x=b on output */
Entry X [ ]
) ;
void KLU_usolve
(
/* inputs, not modified: */
Int n,
Int Up [ ],
Int Ui [ ],
Unit LU [ ],
Entry Udiag [ ],
Int nrhs,
/* right-hand-side on input, solution to Ux=b on output */
Entry X [ ]
) ;
void KLU_utsolve
(
/* inputs, not modified: */
Int n,
Int Up [ ],
Int Ui [ ],
Unit LU [ ],
Entry Udiag [ ],
Int nrhs,
#ifdef COMPLEX
Int conj_solve,
#endif
/* right-hand-side on input, solution to U'x=b on output */
Entry X [ ]
) ;
Int KLU_valid
(
Int n,
Int Ap [ ],
Int Ai [ ],
Entry Ax [ ]
) ;
Int KLU_valid_LU
(
Int n,
Int flag_test_start_ptr,
Int Xip [ ],
Int Xlen [ ],
Unit LU [ ]
);
size_t KLU_add_size_t (size_t a, size_t b, Int *ok) ;
size_t KLU_mult_size_t (size_t a, size_t k, Int *ok) ;
KLU_symbolic *KLU_alloc_symbolic (Int n, Int *Ap, Int *Ai, KLU_common *Common) ;
#endif

1009
src/maths/KLU/klu_kernel.c Normal file

File diff suppressed because it is too large Load Diff

225
src/maths/KLU/klu_memory.c Normal file
View File

@ -0,0 +1,225 @@
/* ========================================================================== */
/* === KLU_memory =========================================================== */
/* ========================================================================== */
/* KLU memory management routines:
*
* KLU_malloc malloc wrapper
* KLU_free free wrapper
* KLU_realloc realloc wrapper
*/
#include "klu_internal.h"
/* ========================================================================== */
/* === KLU_add_size_t ======================================================= */
/* ========================================================================== */
/* Safely compute a+b, and check for size_t overflow */
size_t KLU_add_size_t (size_t a, size_t b, Int *ok)
{
(*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
return ((*ok) ? (a + b) : ((size_t) -1)) ;
}
/* ========================================================================== */
/* === KLU_mult_size_t ====================================================== */
/* ========================================================================== */
/* Safely compute a*k, where k should be small, and check for size_t overflow */
size_t KLU_mult_size_t (size_t a, size_t k, Int *ok)
{
size_t i, s = 0 ;
for (i = 0 ; i < k ; i++)
{
s = KLU_add_size_t (s, a, ok) ;
}
return ((*ok) ? s : ((size_t) -1)) ;
}
/* ========================================================================== */
/* === KLU_malloc =========================================================== */
/* ========================================================================== */
/* Wrapper around malloc routine (mxMalloc for a mexFunction). Allocates
* space of size MAX(1,n)*size, where size is normally a sizeof (...).
*
* This routine and KLU_realloc do not set Common->status to KLU_OK on success,
* so that a sequence of KLU_malloc's or KLU_realloc's can be used. If any of
* them fails, the Common->status will hold the most recent error status.
*
* Usage, for a pointer to Int:
*
* p = KLU_malloc (n, sizeof (Int), Common)
*
* Uses a pointer to the malloc routine (or its equivalent) defined in Common.
*/
void *KLU_malloc /* returns pointer to the newly malloc'd block */
(
/* ---- input ---- */
size_t n, /* number of items */
size_t size, /* size of each item */
/* --------------- */
KLU_common *Common
)
{
void *p ;
size_t s ;
Int ok = TRUE ;
if (Common == NULL)
{
p = NULL ;
}
else if (size == 0)
{
/* size must be > 0 */
Common->status = KLU_INVALID ;
p = NULL ;
}
else if (n >= INT_MAX)
{
/* object is too big to allocate; p[i] where i is an Int will not
* be enough. */
Common->status = KLU_TOO_LARGE ;
p = NULL ;
}
else
{
/* call malloc, or its equivalent */
s = KLU_mult_size_t (MAX (1,n), size, &ok) ;
p = ok ? ((Common->malloc_memory) (s)) : NULL ;
if (p == NULL)
{
/* failure: out of memory */
Common->status = KLU_OUT_OF_MEMORY ;
}
else
{
Common->memusage += s ;
Common->mempeak = MAX (Common->mempeak, Common->memusage) ;
}
}
return (p) ;
}
/* ========================================================================== */
/* === KLU_free ============================================================= */
/* ========================================================================== */
/* Wrapper around free routine (mxFree for a mexFunction). Returns NULL,
* which can be assigned to the pointer being freed, as in:
*
* p = KLU_free (p, n, sizeof (int), Common) ;
*/
void *KLU_free /* always returns NULL */
(
/* ---- in/out --- */
void *p, /* block of memory to free */
/* ---- input --- */
size_t n, /* size of block to free, in # of items */
size_t size, /* size of each item */
/* --------------- */
KLU_common *Common
)
{
size_t s ;
Int ok = TRUE ;
if (p != NULL && Common != NULL)
{
/* only free the object if the pointer is not NULL */
/* call free, or its equivalent */
(Common->free_memory) (p) ;
s = KLU_mult_size_t (MAX (1,n), size, &ok) ;
Common->memusage -= s ;
}
/* return NULL, and the caller should assign this to p. This avoids
* freeing the same pointer twice. */
return (NULL) ;
}
/* ========================================================================== */
/* === KLU_realloc ========================================================== */
/* ========================================================================== */
/* Wrapper around realloc routine (mxRealloc for a mexFunction). Given a
* pointer p to a block allocated by KLU_malloc, it changes the size of the
* block pointed to by p to be MAX(1,nnew)*size in size. It may return a
* pointer different than p. This should be used as (for a pointer to Int):
*
* p = KLU_realloc (nnew, nold, sizeof (Int), p, Common) ;
*
* If p is NULL, this is the same as p = KLU_malloc (...).
* A size of nnew=0 is treated as nnew=1.
*
* If the realloc fails, p is returned unchanged and Common->status is set
* to KLU_OUT_OF_MEMORY. If successful, Common->status is not modified,
* and p is returned (possibly changed) and pointing to a large block of memory.
*
* Uses a pointer to the realloc routine (or its equivalent) defined in Common.
*/
void *KLU_realloc /* returns pointer to reallocated block */
(
/* ---- input ---- */
size_t nnew, /* requested # of items in reallocated block */
size_t nold, /* old # of items */
size_t size, /* size of each item */
/* ---- in/out --- */
void *p, /* block of memory to realloc */
/* --------------- */
KLU_common *Common
)
{
void *pnew ;
size_t snew, sold ;
Int ok = TRUE ;
if (Common == NULL)
{
p = NULL ;
}
else if (size == 0)
{
/* size must be > 0 */
Common->status = KLU_INVALID ;
p = NULL ;
}
else if (p == NULL)
{
/* A fresh object is being allocated. */
p = KLU_malloc (nnew, size, Common) ;
}
else if (nnew >= INT_MAX)
{
/* failure: nnew is too big. Do not change p */
Common->status = KLU_TOO_LARGE ;
}
else
{
/* The object exists, and is changing to some other nonzero size. */
/* call realloc, or its equivalent */
snew = KLU_mult_size_t (MAX (1,nnew), size, &ok) ;
sold = KLU_mult_size_t (MAX (1,nold), size, &ok) ;
pnew = ok ? ((Common->realloc_memory) (p, snew)) : NULL ;
if (pnew == NULL)
{
/* Do not change p, since it still points to allocated memory */
Common->status = KLU_OUT_OF_MEMORY ;
}
else
{
/* success: return the new p and change the size of the block */
Common->memusage += (snew - sold) ;
Common->mempeak = MAX (Common->mempeak, Common->memusage) ;
p = pnew ;
}
}
return (p) ;
}

View File

@ -0,0 +1,478 @@
/* ========================================================================== */
/* === KLU_refactor ========================================================= */
/* ========================================================================== */
/* Factor the matrix, after ordering and analyzing it with KLU_analyze, and
* factoring it once with KLU_factor. This routine cannot do any numerical
* pivoting. The pattern of the input matrix (Ap, Ai) must be identical to
* the pattern given to KLU_factor.
*/
#include "klu_internal.h"
/* ========================================================================== */
/* === KLU_refactor ========================================================= */
/* ========================================================================== */
Int KLU_refactor /* returns TRUE if successful, FALSE otherwise */
(
/* inputs, not modified */
Int Ap [ ], /* size n+1, column pointers */
Int Ai [ ], /* size nz, row indices */
double Ax [ ],
KLU_symbolic *Symbolic,
/* input/output */
KLU_numeric *Numeric,
KLU_common *Common
)
{
Entry ukk, ujk, s ;
Entry *Offx, *Lx, *Ux, *X, *Az, *Udiag ;
double *Rs ;
Int *P, *Q, *R, *Pnum, *Offp, *Offi, *Ui, *Li, *Pinv, *Lip, *Uip, *Llen,
*Ulen ;
Unit **LUbx ;
Unit *LU ;
Int k1, k2, nk, k, block, oldcol, pend, oldrow, n, p, newrow, scale,
nblocks, poff, i, j, up, ulen, llen, maxblock, nzoff ;
/* ---------------------------------------------------------------------- */
/* check inputs */
/* ---------------------------------------------------------------------- */
if (Common == NULL)
{
return (FALSE) ;
}
Common->status = KLU_OK ;
if (Numeric == NULL)
{
/* invalid Numeric object */
Common->status = KLU_INVALID ;
return (FALSE) ;
}
Common->numerical_rank = EMPTY ;
Common->singular_col = EMPTY ;
Az = (Entry *) Ax ;
/* ---------------------------------------------------------------------- */
/* get the contents of the Symbolic object */
/* ---------------------------------------------------------------------- */
n = Symbolic->n ;
P = Symbolic->P ;
Q = Symbolic->Q ;
R = Symbolic->R ;
nblocks = Symbolic->nblocks ;
maxblock = Symbolic->maxblock ;
/* ---------------------------------------------------------------------- */
/* get the contents of the Numeric object */
/* ---------------------------------------------------------------------- */
Pnum = Numeric->Pnum ;
Offp = Numeric->Offp ;
Offi = Numeric->Offi ;
Offx = (Entry *) Numeric->Offx ;
LUbx = (Unit **) Numeric->LUbx ;
scale = Common->scale ;
if (scale > 0)
{
/* factorization was not scaled, but refactorization is scaled */
if (Numeric->Rs == NULL)
{
Numeric->Rs = KLU_malloc (n, sizeof (double), Common) ;
if (Common->status < KLU_OK)
{
Common->status = KLU_OUT_OF_MEMORY ;
return (FALSE) ;
}
}
}
else
{
/* no scaling for refactorization; ensure Numeric->Rs is freed. This
* does nothing if Numeric->Rs is already NULL. */
Numeric->Rs = KLU_free (Numeric->Rs, n, sizeof (double), Common) ;
}
Rs = Numeric->Rs ;
Pinv = Numeric->Pinv ;
X = (Entry *) Numeric->Xwork ;
Common->nrealloc = 0 ;
Udiag = Numeric->Udiag ;
nzoff = Symbolic->nzoff ;
/* ---------------------------------------------------------------------- */
/* check the input matrix compute the row scale factors, Rs */
/* ---------------------------------------------------------------------- */
/* do no scale, or check the input matrix, if scale < 0 */
if (scale >= 0)
{
/* check for out-of-range indices, but do not check for duplicates */
if (!KLU_scale (scale, n, Ap, Ai, Ax, Rs, NULL, Common))
{
return (FALSE) ;
}
}
/* ---------------------------------------------------------------------- */
/* clear workspace X */
/* ---------------------------------------------------------------------- */
for (k = 0 ; k < maxblock ; k++)
{
/* X [k] = 0 */
CLEAR (X [k]) ;
}
poff = 0 ;
/* ---------------------------------------------------------------------- */
/* factor each block */
/* ---------------------------------------------------------------------- */
if (scale <= 0)
{
/* ------------------------------------------------------------------ */
/* no scaling */
/* ------------------------------------------------------------------ */
for (block = 0 ; block < nblocks ; block++)
{
/* -------------------------------------------------------------- */
/* the block is from rows/columns k1 to k2-1 */
/* -------------------------------------------------------------- */
k1 = R [block] ;
k2 = R [block+1] ;
nk = k2 - k1 ;
if (nk == 1)
{
/* ---------------------------------------------------------- */
/* singleton case */
/* ---------------------------------------------------------- */
oldcol = Q [k1] ;
pend = Ap [oldcol+1] ;
CLEAR (s) ;
for (p = Ap [oldcol] ; p < pend ; p++)
{
newrow = Pinv [Ai [p]] - k1 ;
if (newrow < 0 && poff < nzoff)
{
/* entry in off-diagonal block */
Offx [poff] = Az [p] ;
poff++ ;
}
else
{
/* singleton */
s = Az [p] ;
}
}
Udiag [k1] = s ;
}
else
{
/* ---------------------------------------------------------- */
/* construct and factor the kth block */
/* ---------------------------------------------------------- */
Lip = Numeric->Lip + k1 ;
Llen = Numeric->Llen + k1 ;
Uip = Numeric->Uip + k1 ;
Ulen = Numeric->Ulen + k1 ;
LU = LUbx [block] ;
for (k = 0 ; k < nk ; k++)
{
/* ------------------------------------------------------ */
/* scatter kth column of the block into workspace X */
/* ------------------------------------------------------ */
oldcol = Q [k+k1] ;
pend = Ap [oldcol+1] ;
for (p = Ap [oldcol] ; p < pend ; p++)
{
newrow = Pinv [Ai [p]] - k1 ;
if (newrow < 0 && poff < nzoff)
{
/* entry in off-diagonal block */
Offx [poff] = Az [p] ;
poff++ ;
}
else
{
/* (newrow,k) is an entry in the block */
X [newrow] = Az [p] ;
}
}
/* ------------------------------------------------------ */
/* compute kth column of U, and update kth column of A */
/* ------------------------------------------------------ */
GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, ulen) ;
for (up = 0 ; up < ulen ; up++)
{
j = Ui [up] ;
ujk = X [j] ;
/* X [j] = 0 */
CLEAR (X [j]) ;
Ux [up] = ujk ;
GET_POINTER (LU, Lip, Llen, Li, Lx, j, llen) ;
for (p = 0 ; p < llen ; p++)
{
/* X [Li [p]] -= Lx [p] * ujk */
MULT_SUB (X [Li [p]], Lx [p], ujk) ;
}
}
/* get the diagonal entry of U */
ukk = X [k] ;
/* X [k] = 0 */
CLEAR (X [k]) ;
/* singular case */
if (IS_ZERO (ukk))
{
/* matrix is numerically singular */
Common->status = KLU_SINGULAR ;
if (Common->numerical_rank == EMPTY)
{
Common->numerical_rank = k+k1 ;
Common->singular_col = Q [k+k1] ;
}
if (Common->halt_if_singular)
{
/* do not continue the factorization */
return (FALSE) ;
}
}
Udiag [k+k1] = ukk ;
/* gather and divide by pivot to get kth column of L */
GET_POINTER (LU, Lip, Llen, Li, Lx, k, llen) ;
for (p = 0 ; p < llen ; p++)
{
i = Li [p] ;
DIV (Lx [p], X [i], ukk) ;
CLEAR (X [i]) ;
}
}
}
}
}
else
{
/* ------------------------------------------------------------------ */
/* scaling */
/* ------------------------------------------------------------------ */
for (block = 0 ; block < nblocks ; block++)
{
/* -------------------------------------------------------------- */
/* the block is from rows/columns k1 to k2-1 */
/* -------------------------------------------------------------- */
k1 = R [block] ;
k2 = R [block+1] ;
nk = k2 - k1 ;
if (nk == 1)
{
/* ---------------------------------------------------------- */
/* singleton case */
/* ---------------------------------------------------------- */
oldcol = Q [k1] ;
pend = Ap [oldcol+1] ;
CLEAR (s) ;
for (p = Ap [oldcol] ; p < pend ; p++)
{
oldrow = Ai [p] ;
newrow = Pinv [oldrow] - k1 ;
if (newrow < 0 && poff < nzoff)
{
/* entry in off-diagonal block */
/* Offx [poff] = Az [p] / Rs [oldrow] */
SCALE_DIV_ASSIGN (Offx [poff], Az [p], Rs [oldrow]) ;
poff++ ;
}
else
{
/* singleton */
/* s = Az [p] / Rs [oldrow] */
SCALE_DIV_ASSIGN (s, Az [p], Rs [oldrow]) ;
}
}
Udiag [k1] = s ;
}
else
{
/* ---------------------------------------------------------- */
/* construct and factor the kth block */
/* ---------------------------------------------------------- */
Lip = Numeric->Lip + k1 ;
Llen = Numeric->Llen + k1 ;
Uip = Numeric->Uip + k1 ;
Ulen = Numeric->Ulen + k1 ;
LU = LUbx [block] ;
for (k = 0 ; k < nk ; k++)
{
/* ------------------------------------------------------ */
/* scatter kth column of the block into workspace X */
/* ------------------------------------------------------ */
oldcol = Q [k+k1] ;
pend = Ap [oldcol+1] ;
for (p = Ap [oldcol] ; p < pend ; p++)
{
oldrow = Ai [p] ;
newrow = Pinv [oldrow] - k1 ;
if (newrow < 0 && poff < nzoff)
{
/* entry in off-diagonal part */
/* Offx [poff] = Az [p] / Rs [oldrow] */
SCALE_DIV_ASSIGN (Offx [poff], Az [p], Rs [oldrow]);
poff++ ;
}
else
{
/* (newrow,k) is an entry in the block */
/* X [newrow] = Az [p] / Rs [oldrow] */
SCALE_DIV_ASSIGN (X [newrow], Az [p], Rs [oldrow]) ;
}
}
/* ------------------------------------------------------ */
/* compute kth column of U, and update kth column of A */
/* ------------------------------------------------------ */
GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, ulen) ;
for (up = 0 ; up < ulen ; up++)
{
j = Ui [up] ;
ujk = X [j] ;
/* X [j] = 0 */
CLEAR (X [j]) ;
Ux [up] = ujk ;
GET_POINTER (LU, Lip, Llen, Li, Lx, j, llen) ;
for (p = 0 ; p < llen ; p++)
{
/* X [Li [p]] -= Lx [p] * ujk */
MULT_SUB (X [Li [p]], Lx [p], ujk) ;
}
}
/* get the diagonal entry of U */
ukk = X [k] ;
/* X [k] = 0 */
CLEAR (X [k]) ;
/* singular case */
if (IS_ZERO (ukk))
{
/* matrix is numerically singular */
Common->status = KLU_SINGULAR ;
if (Common->numerical_rank == EMPTY)
{
Common->numerical_rank = k+k1 ;
Common->singular_col = Q [k+k1] ;
}
if (Common->halt_if_singular)
{
/* do not continue the factorization */
return (FALSE) ;
}
}
Udiag [k+k1] = ukk ;
/* gather and divide by pivot to get kth column of L */
GET_POINTER (LU, Lip, Llen, Li, Lx, k, llen) ;
for (p = 0 ; p < llen ; p++)
{
i = Li [p] ;
DIV (Lx [p], X [i], ukk) ;
CLEAR (X [i]) ;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
/* permute scale factors Rs according to pivotal row order */
/* ---------------------------------------------------------------------- */
if (scale > 0)
{
for (k = 0 ; k < n ; k++)
{
REAL (X [k]) = Rs [Pnum [k]] ;
}
for (k = 0 ; k < n ; k++)
{
Rs [k] = REAL (X [k]) ;
}
}
#ifndef NDEBUG
ASSERT (Offp [n] == poff) ;
ASSERT (Symbolic->nzoff == poff) ;
PRINTF (("\n------------------- Off diagonal entries, new:\n")) ;
ASSERT (KLU_valid (n, Offp, Offi, Offx)) ;
if (Common->status == KLU_OK)
{
PRINTF (("\n ########### KLU_BTF_REFACTOR done, nblocks %d\n",nblocks));
for (block = 0 ; block < nblocks ; block++)
{
k1 = R [block] ;
k2 = R [block+1] ;
nk = k2 - k1 ;
PRINTF ((
"\n================KLU_refactor output: k1 %d k2 %d nk %d\n",
k1, k2, nk)) ;
if (nk == 1)
{
PRINTF (("singleton ")) ;
PRINT_ENTRY (Udiag [k1]) ;
}
else
{
Lip = Numeric->Lip + k1 ;
Llen = Numeric->Llen + k1 ;
LU = (Unit *) Numeric->LUbx [block] ;
PRINTF (("\n---- L block %d\n", block)) ;
ASSERT (KLU_valid_LU (nk, TRUE, Lip, Llen, LU)) ;
Uip = Numeric->Uip + k1 ;
Ulen = Numeric->Ulen + k1 ;
PRINTF (("\n---- U block %d\n", block)) ;
ASSERT (KLU_valid_LU (nk, FALSE, Uip, Ulen, LU)) ;
}
}
}
#endif
return (TRUE) ;
}

159
src/maths/KLU/klu_scale.c Normal file
View File

@ -0,0 +1,159 @@
/* ========================================================================== */
/* === KLU_scale ============================================================ */
/* ========================================================================== */
/* Scale a matrix and check to see if it is valid. Can be called by the user.
* This is called by KLU_factor and KLU_refactor. Returns TRUE if the input
* matrix is valid, FALSE otherwise. If the W input argument is non-NULL,
* then the input matrix is checked for duplicate entries.
*
* scaling methods:
* <0: no scaling, do not compute Rs, and do not check input matrix.
* 0: no scaling
* 1: the scale factor for row i is sum (abs (A (i,:)))
* 2 or more: the scale factor for row i is max (abs (A (i,:)))
*/
#include "klu_internal.h"
Int KLU_scale /* return TRUE if successful, FALSE otherwise */
(
/* inputs, not modified */
Int scale, /* 0: none, 1: sum, 2: max */
Int n,
Int Ap [ ], /* size n+1, column pointers */
Int Ai [ ], /* size nz, row indices */
double Ax [ ],
/* outputs, not defined on input */
double Rs [ ], /* size n, can be NULL if scale <= 0 */
/* workspace, not defined on input or output */
Int W [ ], /* size n, can be NULL */
/* --------------- */
KLU_common *Common
)
{
double a ;
Entry *Az ;
Int row, col, p, pend, check_duplicates ;
/* ---------------------------------------------------------------------- */
/* check inputs */
/* ---------------------------------------------------------------------- */
if (Common == NULL)
{
return (FALSE) ;
}
Common->status = KLU_OK ;
if (scale < 0)
{
/* return without checking anything and without computing the
* scale factors */
return (TRUE) ;
}
Az = (Entry *) Ax ;
if (n <= 0 || Ap == NULL || Ai == NULL || Az == NULL ||
(scale > 0 && Rs == NULL))
{
/* Ap, Ai, Ax and Rs must be present, and n must be > 0 */
Common->status = KLU_INVALID ;
return (FALSE) ;
}
if (Ap [0] != 0 || Ap [n] < 0)
{
/* nz = Ap [n] must be >= 0 and Ap [0] must equal zero */
Common->status = KLU_INVALID ;
return (FALSE) ;
}
for (col = 0 ; col < n ; col++)
{
if (Ap [col] > Ap [col+1])
{
/* column pointers must be non-decreasing */
Common->status = KLU_INVALID ;
return (FALSE) ;
}
}
/* ---------------------------------------------------------------------- */
/* scale */
/* ---------------------------------------------------------------------- */
if (scale > 0)
{
/* initialize row sum or row max */
for (row = 0 ; row < n ; row++)
{
Rs [row] = 0 ;
}
}
/* check for duplicates only if W is present */
check_duplicates = (W != (Int *) NULL) ;
if (check_duplicates)
{
for (row = 0 ; row < n ; row++)
{
W [row] = EMPTY ;
}
}
for (col = 0 ; col < n ; col++)
{
pend = Ap [col+1] ;
for (p = Ap [col] ; p < pend ; p++)
{
row = Ai [p] ;
if (row < 0 || row >= n)
{
/* row index out of range, or duplicate entry */
Common->status = KLU_INVALID ;
return (FALSE) ;
}
if (check_duplicates)
{
if (W [row] == col)
{
/* duplicate entry */
Common->status = KLU_INVALID ;
return (FALSE) ;
}
/* flag row i as appearing in column col */
W [row] = col ;
}
/* a = ABS (Az [p]) ;*/
ABS (a, Az [p]) ;
if (scale == 1)
{
/* accumulate the abs. row sum */
Rs [row] += a ;
}
else if (scale > 1)
{
/* find the max abs. value in the row */
Rs [row] = MAX (Rs [row], a) ;
}
}
}
if (scale > 0)
{
/* do not scale empty rows */
for (row = 0 ; row < n ; row++)
{
/* matrix is singular */
PRINTF (("Rs [%d] = %g\n", row, Rs [row])) ;
if (Rs [row] == 0.0)
{
PRINTF (("Row %d of A is all zero\n", row)) ;
Rs [row] = 1.0 ;
}
}
}
return (TRUE) ;
}

396
src/maths/KLU/klu_solve.c Normal file
View File

@ -0,0 +1,396 @@
/* ========================================================================== */
/* === KLU_solve ============================================================ */
/* ========================================================================== */
/* Solve Ax=b using the symbolic and numeric objects from KLU_analyze
* (or KLU_analyze_given) and KLU_factor. Note that no iterative refinement is
* performed. Uses Numeric->Xwork as workspace (undefined on input and output),
* of size 4n Entry's (note that columns 2 to 4 of Xwork overlap with
* Numeric->Iwork).
*/
#include "klu_internal.h"
Int KLU_solve
(
/* inputs, not modified */
KLU_symbolic *Symbolic,
KLU_numeric *Numeric,
Int d, /* leading dimension of B */
Int nrhs, /* number of right-hand-sides */
/* right-hand-side on input, overwritten with solution to Ax=b on output */
double B [ ], /* size n*nrhs, in column-oriented form, with
* leading dimension d. */
/* --------------- */
KLU_common *Common
)
{
Entry x [4], offik, s ;
double rs, *Rs ;
Entry *Offx, *X, *Bz, *Udiag ;
Int *Q, *R, *Pnum, *Offp, *Offi, *Lip, *Uip, *Llen, *Ulen ;
Unit **LUbx ;
Int k1, k2, nk, k, block, pend, n, p, nblocks, chunk, nr, i ;
/* ---------------------------------------------------------------------- */
/* check inputs */
/* ---------------------------------------------------------------------- */
if (Common == NULL)
{
return (FALSE) ;
}
if (Numeric == NULL || Symbolic == NULL || d < Symbolic->n || nrhs < 0 ||
B == NULL)
{
Common->status = KLU_INVALID ;
return (FALSE) ;
}
Common->status = KLU_OK ;
/* ---------------------------------------------------------------------- */
/* get the contents of the Symbolic object */
/* ---------------------------------------------------------------------- */
Bz = (Entry *) B ;
n = Symbolic->n ;
nblocks = Symbolic->nblocks ;
Q = Symbolic->Q ;
R = Symbolic->R ;
/* ---------------------------------------------------------------------- */
/* get the contents of the Numeric object */
/* ---------------------------------------------------------------------- */
ASSERT (nblocks == Numeric->nblocks) ;
Pnum = Numeric->Pnum ;
Offp = Numeric->Offp ;
Offi = Numeric->Offi ;
Offx = (Entry *) Numeric->Offx ;
Lip = Numeric->Lip ;
Llen = Numeric->Llen ;
Uip = Numeric->Uip ;
Ulen = Numeric->Ulen ;
LUbx = (Unit **) Numeric->LUbx ;
Udiag = Numeric->Udiag ;
Rs = Numeric->Rs ;
X = (Entry *) Numeric->Xwork ;
ASSERT (KLU_valid (n, Offp, Offi, Offx)) ;
/* ---------------------------------------------------------------------- */
/* solve in chunks of 4 columns at a time */
/* ---------------------------------------------------------------------- */
for (chunk = 0 ; chunk < nrhs ; chunk += 4)
{
/* ------------------------------------------------------------------ */
/* get the size of the current chunk */
/* ------------------------------------------------------------------ */
nr = MIN (nrhs - chunk, 4) ;
/* ------------------------------------------------------------------ */
/* scale and permute the right hand side, X = P*(R\B) */
/* ------------------------------------------------------------------ */
if (Rs == NULL)
{
/* no scaling */
switch (nr)
{
case 1:
for (k = 0 ; k < n ; k++)
{
X [k] = Bz [Pnum [k]] ;
}
break ;
case 2:
for (k = 0 ; k < n ; k++)
{
i = Pnum [k] ;
X [2*k ] = Bz [i ] ;
X [2*k + 1] = Bz [i + d ] ;
}
break ;
case 3:
for (k = 0 ; k < n ; k++)
{
i = Pnum [k] ;
X [3*k ] = Bz [i ] ;
X [3*k + 1] = Bz [i + d ] ;
X [3*k + 2] = Bz [i + d*2] ;
}
break ;
case 4:
for (k = 0 ; k < n ; k++)
{
i = Pnum [k] ;
X [4*k ] = Bz [i ] ;
X [4*k + 1] = Bz [i + d ] ;
X [4*k + 2] = Bz [i + d*2] ;
X [4*k + 3] = Bz [i + d*3] ;
}
break ;
}
}
else
{
switch (nr)
{
case 1:
for (k = 0 ; k < n ; k++)
{
SCALE_DIV_ASSIGN (X [k], Bz [Pnum [k]], Rs [k]) ;
}
break ;
case 2:
for (k = 0 ; k < n ; k++)
{
i = Pnum [k] ;
rs = Rs [k] ;
SCALE_DIV_ASSIGN (X [2*k], Bz [i], rs) ;
SCALE_DIV_ASSIGN (X [2*k + 1], Bz [i + d], rs) ;
}
break ;
case 3:
for (k = 0 ; k < n ; k++)
{
i = Pnum [k] ;
rs = Rs [k] ;
SCALE_DIV_ASSIGN (X [3*k], Bz [i], rs) ;
SCALE_DIV_ASSIGN (X [3*k + 1], Bz [i + d], rs) ;
SCALE_DIV_ASSIGN (X [3*k + 2], Bz [i + d*2], rs) ;
}
break ;
case 4:
for (k = 0 ; k < n ; k++)
{
i = Pnum [k] ;
rs = Rs [k] ;
SCALE_DIV_ASSIGN (X [4*k], Bz [i], rs) ;
SCALE_DIV_ASSIGN (X [4*k + 1], Bz [i + d], rs) ;
SCALE_DIV_ASSIGN (X [4*k + 2], Bz [i + d*2], rs) ;
SCALE_DIV_ASSIGN (X [4*k + 3], Bz [i + d*3], rs) ;
}
break ;
}
}
/* ------------------------------------------------------------------ */
/* solve X = (L*U + Off)\X */
/* ------------------------------------------------------------------ */
for (block = nblocks-1 ; block >= 0 ; block--)
{
/* -------------------------------------------------------------- */
/* the block of size nk is from rows/columns k1 to k2-1 */
/* -------------------------------------------------------------- */
k1 = R [block] ;
k2 = R [block+1] ;
nk = k2 - k1 ;
PRINTF (("solve %d, k1 %d k2-1 %d nk %d\n", block, k1,k2-1,nk)) ;
/* solve the block system */
if (nk == 1)
{
s = Udiag [k1] ;
switch (nr)
{
case 1:
DIV (X [k1], X [k1], s) ;
break ;
case 2:
DIV (X [2*k1], X [2*k1], s) ;
DIV (X [2*k1 + 1], X [2*k1 + 1], s) ;
break ;
case 3:
DIV (X [3*k1], X [3*k1], s) ;
DIV (X [3*k1 + 1], X [3*k1 + 1], s) ;
DIV (X [3*k1 + 2], X [3*k1 + 2], s) ;
break ;
case 4:
DIV (X [4*k1], X [4*k1], s) ;
DIV (X [4*k1 + 1], X [4*k1 + 1], s) ;
DIV (X [4*k1 + 2], X [4*k1 + 2], s) ;
DIV (X [4*k1 + 3], X [4*k1 + 3], s) ;
break ;
}
}
else
{
KLU_lsolve (nk, Lip + k1, Llen + k1, LUbx [block], nr,
X + nr*k1) ;
KLU_usolve (nk, Uip + k1, Ulen + k1, LUbx [block],
Udiag + k1, nr, X + nr*k1) ;
}
/* -------------------------------------------------------------- */
/* block back-substitution for the off-diagonal-block entries */
/* -------------------------------------------------------------- */
if (block > 0)
{
switch (nr)
{
case 1:
for (k = k1 ; k < k2 ; k++)
{
pend = Offp [k+1] ;
x [0] = X [k] ;
for (p = Offp [k] ; p < pend ; p++)
{
MULT_SUB (X [Offi [p]], Offx [p], x [0]) ;
}
}
break ;
case 2:
for (k = k1 ; k < k2 ; k++)
{
pend = Offp [k+1] ;
x [0] = X [2*k ] ;
x [1] = X [2*k + 1] ;
for (p = Offp [k] ; p < pend ; p++)
{
i = Offi [p] ;
offik = Offx [p] ;
MULT_SUB (X [2*i], offik, x [0]) ;
MULT_SUB (X [2*i + 1], offik, x [1]) ;
}
}
break ;
case 3:
for (k = k1 ; k < k2 ; k++)
{
pend = Offp [k+1] ;
x [0] = X [3*k ] ;
x [1] = X [3*k + 1] ;
x [2] = X [3*k + 2] ;
for (p = Offp [k] ; p < pend ; p++)
{
i = Offi [p] ;
offik = Offx [p] ;
MULT_SUB (X [3*i], offik, x [0]) ;
MULT_SUB (X [3*i + 1], offik, x [1]) ;
MULT_SUB (X [3*i + 2], offik, x [2]) ;
}
}
break ;
case 4:
for (k = k1 ; k < k2 ; k++)
{
pend = Offp [k+1] ;
x [0] = X [4*k ] ;
x [1] = X [4*k + 1] ;
x [2] = X [4*k + 2] ;
x [3] = X [4*k + 3] ;
for (p = Offp [k] ; p < pend ; p++)
{
i = Offi [p] ;
offik = Offx [p] ;
MULT_SUB (X [4*i], offik, x [0]) ;
MULT_SUB (X [4*i + 1], offik, x [1]) ;
MULT_SUB (X [4*i + 2], offik, x [2]) ;
MULT_SUB (X [4*i + 3], offik, x [3]) ;
}
}
break ;
}
}
}
/* ------------------------------------------------------------------ */
/* permute the result, Bz = Q*X */
/* ------------------------------------------------------------------ */
switch (nr)
{
case 1:
for (k = 0 ; k < n ; k++)
{
Bz [Q [k]] = X [k] ;
}
break ;
case 2:
for (k = 0 ; k < n ; k++)
{
i = Q [k] ;
Bz [i ] = X [2*k ] ;
Bz [i + d ] = X [2*k + 1] ;
}
break ;
case 3:
for (k = 0 ; k < n ; k++)
{
i = Q [k] ;
Bz [i ] = X [3*k ] ;
Bz [i + d ] = X [3*k + 1] ;
Bz [i + d*2] = X [3*k + 2] ;
}
break ;
case 4:
for (k = 0 ; k < n ; k++)
{
i = Q [k] ;
Bz [i ] = X [4*k ] ;
Bz [i + d ] = X [4*k + 1] ;
Bz [i + d*2] = X [4*k + 2] ;
Bz [i + d*3] = X [4*k + 3] ;
}
break ;
}
/* ------------------------------------------------------------------ */
/* go to the next chunk of B */
/* ------------------------------------------------------------------ */
Bz += d*4 ;
}
return (TRUE) ;
}

156
src/maths/KLU/klu_sort.c Normal file
View File

@ -0,0 +1,156 @@
/* ========================================================================== */
/* === KLU_sort ============================================================= */
/* ========================================================================== */
/* sorts the columns of L and U so that the row indices appear in strictly
* increasing order.
*/
#include "klu_internal.h"
/* ========================================================================== */
/* === sort ================================================================= */
/* ========================================================================== */
/* Sort L or U using a double-transpose */
static void sort (Int n, Int *Xip, Int *Xlen, Unit *LU, Int *Tp, Int *Tj,
Entry *Tx, Int *W)
{
Int *Xi ;
Entry *Xx ;
Int p, i, j, len, nz, tp, xlen, pend ;
ASSERT (KLU_valid_LU (n, FALSE, Xip, Xlen, LU)) ;
/* count the number of entries in each row of L or U */
for (i = 0 ; i < n ; i++)
{
W [i] = 0 ;
}
for (j = 0 ; j < n ; j++)
{
GET_POINTER (LU, Xip, Xlen, Xi, Xx, j, len) ;
for (p = 0 ; p < len ; p++)
{
W [Xi [p]]++ ;
}
}
/* construct the row pointers for T */
nz = 0 ;
for (i = 0 ; i < n ; i++)
{
Tp [i] = nz ;
nz += W [i] ;
}
Tp [n] = nz ;
for (i = 0 ; i < n ; i++)
{
W [i] = Tp [i] ;
}
/* transpose the matrix into Tp, Ti, Tx */
for (j = 0 ; j < n ; j++)
{
GET_POINTER (LU, Xip, Xlen, Xi, Xx, j, len) ;
for (p = 0 ; p < len ; p++)
{
tp = W [Xi [p]]++ ;
Tj [tp] = j ;
Tx [tp] = Xx [p] ;
}
}
/* transpose the matrix back into Xip, Xlen, Xi, Xx */
for (j = 0 ; j < n ; j++)
{
W [j] = 0 ;
}
for (i = 0 ; i < n ; i++)
{
pend = Tp [i+1] ;
for (p = Tp [i] ; p < pend ; p++)
{
j = Tj [p] ;
GET_POINTER (LU, Xip, Xlen, Xi, Xx, j, len) ;
xlen = W [j]++ ;
Xi [xlen] = i ;
Xx [xlen] = Tx [p] ;
}
}
ASSERT (KLU_valid_LU (n, FALSE, Xip, Xlen, LU)) ;
}
/* ========================================================================== */
/* === KLU_sort ============================================================= */
/* ========================================================================== */
Int KLU_sort
(
KLU_symbolic *Symbolic,
KLU_numeric *Numeric,
KLU_common *Common
)
{
Int *R, *W, *Tp, *Ti, *Lip, *Uip, *Llen, *Ulen ;
Entry *Tx ;
Unit **LUbx ;
Int n, nk, nz, block, nblocks, maxblock, k1 ;
size_t m1 ;
if (Common == NULL)
{
return (FALSE) ;
}
Common->status = KLU_OK ;
n = Symbolic->n ;
R = Symbolic->R ;
nblocks = Symbolic->nblocks ;
maxblock = Symbolic->maxblock ;
Lip = Numeric->Lip ;
Llen = Numeric->Llen ;
Uip = Numeric->Uip ;
Ulen = Numeric->Ulen ;
LUbx = (Unit **) Numeric->LUbx ;
m1 = ((size_t) maxblock) + 1 ;
/* allocate workspace */
nz = MAX (Numeric->max_lnz_block, Numeric->max_unz_block) ;
W = KLU_malloc (maxblock, sizeof (Int), Common) ;
Tp = KLU_malloc (m1, sizeof (Int), Common) ;
Ti = KLU_malloc (nz, sizeof (Int), Common) ;
Tx = KLU_malloc (nz, sizeof (Entry), Common) ;
PRINTF (("\n======================= Start sort:\n")) ;
if (Common->status == KLU_OK)
{
/* sort each block of L and U */
for (block = 0 ; block < nblocks ; block++)
{
k1 = R [block] ;
nk = R [block+1] - k1 ;
if (nk > 1)
{
PRINTF (("\n-------------------block: %d nk %d\n", block, nk)) ;
sort (nk, Lip + k1, Llen + k1, LUbx [block], Tp, Ti, Tx, W) ;
sort (nk, Uip + k1, Ulen + k1, LUbx [block], Tp, Ti, Tx, W) ;
}
}
}
PRINTF (("\n======================= sort done.\n")) ;
/* free workspace */
KLU_free (W, maxblock, sizeof (Int), Common) ;
KLU_free (Tp, m1, sizeof (Int), Common) ;
KLU_free (Ti, nz, sizeof (Int), Common) ;
KLU_free (Tx, nz, sizeof (Entry), Common) ;
return (Common->status == KLU_OK) ;
}

465
src/maths/KLU/klu_tsolve.c Normal file
View File

@ -0,0 +1,465 @@
/* ========================================================================== */
/* === KLU_tsolve =========================================================== */
/* ========================================================================== */
/* Solve A'x=b using the symbolic and numeric objects from KLU_analyze
* (or KLU_analyze_given) and KLU_factor. Note that no iterative refinement is
* performed. Uses Numeric->Xwork as workspace (undefined on input and output),
* of size 4n Entry's (note that columns 2 to 4 of Xwork overlap with
* Numeric->Iwork).
*/
#include "klu_internal.h"
Int KLU_tsolve
(
/* inputs, not modified */
KLU_symbolic *Symbolic,
KLU_numeric *Numeric,
Int d, /* leading dimension of B */
Int nrhs, /* number of right-hand-sides */
/* right-hand-side on input, overwritten with solution to Ax=b on output */
double B [ ], /* size n*nrhs, in column-oriented form, with
* leading dimension d. */
#ifdef COMPLEX
Int conj_solve, /* TRUE for conjugate transpose solve, FALSE for
* array transpose solve. Used for the complex
* case only. */
#endif
/* --------------- */
KLU_common *Common
)
{
Entry x [4], offik, s ;
double rs, *Rs ;
Entry *Offx, *X, *Bz, *Udiag ;
Int *Q, *R, *Pnum, *Offp, *Offi, *Lip, *Uip, *Llen, *Ulen ;
Unit **LUbx ;
Int k1, k2, nk, k, block, pend, n, p, nblocks, chunk, nr, i ;
/* ---------------------------------------------------------------------- */
/* check inputs */
/* ---------------------------------------------------------------------- */
if (Common == NULL)
{
return (FALSE) ;
}
if (Numeric == NULL || Symbolic == NULL || d < Symbolic->n || nrhs < 0 ||
B == NULL)
{
Common->status = KLU_INVALID ;
return (FALSE) ;
}
Common->status = KLU_OK ;
/* ---------------------------------------------------------------------- */
/* get the contents of the Symbolic object */
/* ---------------------------------------------------------------------- */
Bz = (Entry *) B ;
n = Symbolic->n ;
nblocks = Symbolic->nblocks ;
Q = Symbolic->Q ;
R = Symbolic->R ;
/* ---------------------------------------------------------------------- */
/* get the contents of the Numeric object */
/* ---------------------------------------------------------------------- */
ASSERT (nblocks == Numeric->nblocks) ;
Pnum = Numeric->Pnum ;
Offp = Numeric->Offp ;
Offi = Numeric->Offi ;
Offx = (Entry *) Numeric->Offx ;
Lip = Numeric->Lip ;
Llen = Numeric->Llen ;
Uip = Numeric->Uip ;
Ulen = Numeric->Ulen ;
LUbx = (Unit **) Numeric->LUbx ;
Udiag = Numeric->Udiag ;
Rs = Numeric->Rs ;
X = (Entry *) Numeric->Xwork ;
ASSERT (KLU_valid (n, Offp, Offi, Offx)) ;
/* ---------------------------------------------------------------------- */
/* solve in chunks of 4 columns at a time */
/* ---------------------------------------------------------------------- */
for (chunk = 0 ; chunk < nrhs ; chunk += 4)
{
/* ------------------------------------------------------------------ */
/* get the size of the current chunk */
/* ------------------------------------------------------------------ */
nr = MIN (nrhs - chunk, 4) ;
/* ------------------------------------------------------------------ */
/* permute the right hand side, X = Q'*B */
/* ------------------------------------------------------------------ */
switch (nr)
{
case 1:
for (k = 0 ; k < n ; k++)
{
X [k] = Bz [Q [k]] ;
}
break ;
case 2:
for (k = 0 ; k < n ; k++)
{
i = Q [k] ;
X [2*k ] = Bz [i ] ;
X [2*k + 1] = Bz [i + d ] ;
}
break ;
case 3:
for (k = 0 ; k < n ; k++)
{
i = Q [k] ;
X [3*k ] = Bz [i ] ;
X [3*k + 1] = Bz [i + d ] ;
X [3*k + 2] = Bz [i + d*2] ;
}
break ;
case 4:
for (k = 0 ; k < n ; k++)
{
i = Q [k] ;
X [4*k ] = Bz [i ] ;
X [4*k + 1] = Bz [i + d ] ;
X [4*k + 2] = Bz [i + d*2] ;
X [4*k + 3] = Bz [i + d*3] ;
}
break ;
}
/* ------------------------------------------------------------------ */
/* solve X = (L*U + Off)'\X */
/* ------------------------------------------------------------------ */
for (block = 0 ; block < nblocks ; block++)
{
/* -------------------------------------------------------------- */
/* the block of size nk is from rows/columns k1 to k2-1 */
/* -------------------------------------------------------------- */
k1 = R [block] ;
k2 = R [block+1] ;
nk = k2 - k1 ;
PRINTF (("tsolve %d, k1 %d k2-1 %d nk %d\n", block, k1,k2-1,nk)) ;
/* -------------------------------------------------------------- */
/* block back-substitution for the off-diagonal-block entries */
/* -------------------------------------------------------------- */
if (block > 0)
{
switch (nr)
{
case 1:
for (k = k1 ; k < k2 ; k++)
{
pend = Offp [k+1] ;
for (p = Offp [k] ; p < pend ; p++)
{
#ifdef COMPLEX
if (conj_solve)
{
MULT_SUB_CONJ (X [k], X [Offi [p]],
Offx [p]) ;
}
else
#endif
{
MULT_SUB (X [k], Offx [p], X [Offi [p]]) ;
}
}
}
break ;
case 2:
for (k = k1 ; k < k2 ; k++)
{
pend = Offp [k+1] ;
x [0] = X [2*k ] ;
x [1] = X [2*k + 1] ;
for (p = Offp [k] ; p < pend ; p++)
{
i = Offi [p] ;
#ifdef COMPLEX
if (conj_solve)
{
CONJ (offik, Offx [p]) ;
}
else
#endif
{
offik = Offx [p] ;
}
MULT_SUB (x [0], offik, X [2*i]) ;
MULT_SUB (x [1], offik, X [2*i + 1]) ;
}
X [2*k ] = x [0] ;
X [2*k + 1] = x [1] ;
}
break ;
case 3:
for (k = k1 ; k < k2 ; k++)
{
pend = Offp [k+1] ;
x [0] = X [3*k ] ;
x [1] = X [3*k + 1] ;
x [2] = X [3*k + 2] ;
for (p = Offp [k] ; p < pend ; p++)
{
i = Offi [p] ;
#ifdef COMPLEX
if (conj_solve)
{
CONJ (offik, Offx [p]) ;
}
else
#endif
{
offik = Offx [p] ;
}
MULT_SUB (x [0], offik, X [3*i]) ;
MULT_SUB (x [1], offik, X [3*i + 1]) ;
MULT_SUB (x [2], offik, X [3*i + 2]) ;
}
X [3*k ] = x [0] ;
X [3*k + 1] = x [1] ;
X [3*k + 2] = x [2] ;
}
break ;
case 4:
for (k = k1 ; k < k2 ; k++)
{
pend = Offp [k+1] ;
x [0] = X [4*k ] ;
x [1] = X [4*k + 1] ;
x [2] = X [4*k + 2] ;
x [3] = X [4*k + 3] ;
for (p = Offp [k] ; p < pend ; p++)
{
i = Offi [p] ;
#ifdef COMPLEX
if (conj_solve)
{
CONJ(offik, Offx [p]) ;
}
else
#endif
{
offik = Offx [p] ;
}
MULT_SUB (x [0], offik, X [4*i]) ;
MULT_SUB (x [1], offik, X [4*i + 1]) ;
MULT_SUB (x [2], offik, X [4*i + 2]) ;
MULT_SUB (x [3], offik, X [4*i + 3]) ;
}
X [4*k ] = x [0] ;
X [4*k + 1] = x [1] ;
X [4*k + 2] = x [2] ;
X [4*k + 3] = x [3] ;
}
break ;
}
}
/* -------------------------------------------------------------- */
/* solve the block system */
/* -------------------------------------------------------------- */
if (nk == 1)
{
#ifdef COMPLEX
if (conj_solve)
{
CONJ (s, Udiag [k1]) ;
}
else
#endif
{
s = Udiag [k1] ;
}
switch (nr)
{
case 1:
DIV (X [k1], X [k1], s) ;
break ;
case 2:
DIV (X [2*k1], X [2*k1], s) ;
DIV (X [2*k1 + 1], X [2*k1 + 1], s) ;
break ;
case 3:
DIV (X [3*k1], X [3*k1], s) ;
DIV (X [3*k1 + 1], X [3*k1 + 1], s) ;
DIV (X [3*k1 + 2], X [3*k1 + 2], s) ;
break ;
case 4:
DIV (X [4*k1], X [4*k1], s) ;
DIV (X [4*k1 + 1], X [4*k1 + 1], s) ;
DIV (X [4*k1 + 2], X [4*k1 + 2], s) ;
DIV (X [4*k1 + 3], X [4*k1 + 3], s) ;
break ;
}
}
else
{
KLU_utsolve (nk, Uip + k1, Ulen + k1, LUbx [block],
Udiag + k1, nr,
#ifdef COMPLEX
conj_solve,
#endif
X + nr*k1) ;
KLU_ltsolve (nk, Lip + k1, Llen + k1, LUbx [block], nr,
#ifdef COMPLEX
conj_solve,
#endif
X + nr*k1) ;
}
}
/* ------------------------------------------------------------------ */
/* scale and permute the result, Bz = P'(R\X) */
/* ------------------------------------------------------------------ */
if (Rs == NULL)
{
/* no scaling */
switch (nr)
{
case 1:
for (k = 0 ; k < n ; k++)
{
Bz [Pnum [k]] = X [k] ;
}
break ;
case 2:
for (k = 0 ; k < n ; k++)
{
i = Pnum [k] ;
Bz [i ] = X [2*k ] ;
Bz [i + d ] = X [2*k + 1] ;
}
break ;
case 3:
for (k = 0 ; k < n ; k++)
{
i = Pnum [k] ;
Bz [i ] = X [3*k ] ;
Bz [i + d ] = X [3*k + 1] ;
Bz [i + d*2] = X [3*k + 2] ;
}
break ;
case 4:
for (k = 0 ; k < n ; k++)
{
i = Pnum [k] ;
Bz [i ] = X [4*k ] ;
Bz [i + d ] = X [4*k + 1] ;
Bz [i + d*2] = X [4*k + 2] ;
Bz [i + d*3] = X [4*k + 3] ;
}
break ;
}
}
else
{
switch (nr)
{
case 1:
for (k = 0 ; k < n ; k++)
{
SCALE_DIV_ASSIGN (Bz [Pnum [k]], X [k], Rs [k]) ;
}
break ;
case 2:
for (k = 0 ; k < n ; k++)
{
i = Pnum [k] ;
rs = Rs [k] ;
SCALE_DIV_ASSIGN (Bz [i], X [2*k], rs) ;
SCALE_DIV_ASSIGN (Bz [i + d], X [2*k + 1], rs) ;
}
break ;
case 3:
for (k = 0 ; k < n ; k++)
{
i = Pnum [k] ;
rs = Rs [k] ;
SCALE_DIV_ASSIGN (Bz [i], X [3*k], rs) ;
SCALE_DIV_ASSIGN (Bz [i + d], X [3*k + 1], rs) ;
SCALE_DIV_ASSIGN (Bz [i + d*2], X [3*k + 2], rs) ;
}
break ;
case 4:
for (k = 0 ; k < n ; k++)
{
i = Pnum [k] ;
rs = Rs [k] ;
SCALE_DIV_ASSIGN (Bz [i], X [4*k], rs) ;
SCALE_DIV_ASSIGN (Bz [i + d], X [4*k + 1], rs) ;
SCALE_DIV_ASSIGN (Bz [i + d*2], X [4*k + 2], rs) ;
SCALE_DIV_ASSIGN (Bz [i + d*3], X [4*k + 3], rs) ;
}
break ;
}
}
/* ------------------------------------------------------------------ */
/* go to the next chunk of B */
/* ------------------------------------------------------------------ */
Bz += d*4 ;
}
return (TRUE) ;
}

694
src/maths/KLU/klu_version.h Normal file
View File

@ -0,0 +1,694 @@
#ifndef _KLU_VERSION_H
#define _KLU_VERSION_H
#ifdef DLONG
#define Int UF_long
#define Int_id UF_long_id
#define Int_MAX UF_long_max
#else
#define Int int
#define Int_id "%d"
#define Int_MAX INT_MAX
#endif
#define NPRINT
#define BYTES(type,n) (sizeof (type) * (n))
#define CEILING(b,u) (((b)+(u)-1) / (u))
#define UNITS(type,n) (CEILING (BYTES (type,n), sizeof (Unit)))
#define DUNITS(type,n) (ceil (BYTES (type, (double) n) / sizeof (Unit)))
#define GET_I_POINTER(LU, Xip, Xi, k) \
{ \
Xi = (Int *) (LU + Xip [k]) ; \
}
#define GET_X_POINTER(LU, Xip, Xlen, Xx, k) \
{ \
Xx = (Entry *) (LU + Xip [k] + UNITS (Int, Xlen [k])) ; \
}
#define GET_POINTER(LU, Xip, Xlen, Xi, Xx, k, xlen) \
{ \
Unit *xp = LU + Xip [k] ; \
xlen = Xlen [k] ; \
Xi = (Int *) xp ; \
Xx = (Entry *) (xp + UNITS (Int, xlen)) ; \
}
/* function names */
#ifdef COMPLEX
#ifdef DLONG
#define KLU_scale klu_zl_scale
#define KLU_solve klu_zl_solve
#define KLU_tsolve klu_zl_tsolve
#define KLU_free_numeric klu_zl_free_numeric
#define KLU_factor klu_zl_factor
#define KLU_refactor klu_zl_refactor
#define KLU_kernel_factor klu_zl_kernel_factor
#define KLU_lsolve klu_zl_lsolve
#define KLU_ltsolve klu_zl_ltsolve
#define KLU_usolve klu_zl_usolve
#define KLU_utsolve klu_zl_utsolve
#define KLU_kernel klu_zl_kernel
#define KLU_valid klu_zl_valid
#define KLU_valid_LU klu_zl_valid_LU
#define KLU_sort klu_zl_sort
#define KLU_rgrowth klu_zl_rgrowth
#define KLU_rcond klu_zl_rcond
#define KLU_extract klu_zl_extract
#define KLU_condest klu_zl_condest
#define KLU_flops klu_zl_flops
#else
#define KLU_scale klu_z_scale
#define KLU_solve klu_z_solve
#define KLU_tsolve klu_z_tsolve
#define KLU_free_numeric klu_z_free_numeric
#define KLU_factor klu_z_factor
#define KLU_refactor klu_z_refactor
#define KLU_kernel_factor klu_z_kernel_factor
#define KLU_lsolve klu_z_lsolve
#define KLU_ltsolve klu_z_ltsolve
#define KLU_usolve klu_z_usolve
#define KLU_utsolve klu_z_utsolve
#define KLU_kernel klu_z_kernel
#define KLU_valid klu_z_valid
#define KLU_valid_LU klu_z_valid_LU
#define KLU_sort klu_z_sort
#define KLU_rgrowth klu_z_rgrowth
#define KLU_rcond klu_z_rcond
#define KLU_extract klu_z_extract
#define KLU_condest klu_z_condest
#define KLU_flops klu_z_flops
#endif
#else
#ifdef DLONG
#define KLU_scale klu_l_scale
#define KLU_solve klu_l_solve
#define KLU_tsolve klu_l_tsolve
#define KLU_free_numeric klu_l_free_numeric
#define KLU_factor klu_l_factor
#define KLU_refactor klu_l_refactor
#define KLU_kernel_factor klu_l_kernel_factor
#define KLU_lsolve klu_l_lsolve
#define KLU_ltsolve klu_l_ltsolve
#define KLU_usolve klu_l_usolve
#define KLU_utsolve klu_l_utsolve
#define KLU_kernel klu_l_kernel
#define KLU_valid klu_l_valid
#define KLU_valid_LU klu_l_valid_LU
#define KLU_sort klu_l_sort
#define KLU_rgrowth klu_l_rgrowth
#define KLU_rcond klu_l_rcond
#define KLU_extract klu_l_extract
#define KLU_condest klu_l_condest
#define KLU_flops klu_l_flops
#else
#define KLU_scale klu_scale
#define KLU_solve klu_solve
#define KLU_tsolve klu_tsolve
#define KLU_free_numeric klu_free_numeric
#define KLU_factor klu_factor
#define KLU_refactor klu_refactor
#define KLU_kernel_factor klu_kernel_factor
#define KLU_lsolve klu_lsolve
#define KLU_ltsolve klu_ltsolve
#define KLU_usolve klu_usolve
#define KLU_utsolve klu_utsolve
#define KLU_kernel klu_kernel
#define KLU_valid klu_valid
#define KLU_valid_LU klu_valid_LU
#define KLU_sort klu_sort
#define KLU_rgrowth klu_rgrowth
#define KLU_rcond klu_rcond
#define KLU_extract klu_extract
#define KLU_condest klu_condest
#define KLU_flops klu_flops
#endif
#endif
#ifdef DLONG
#define KLU_analyze klu_l_analyze
#define KLU_analyze_given klu_l_analyze_given
#define KLU_alloc_symbolic klu_l_alloc_symbolic
#define KLU_free_symbolic klu_l_free_symbolic
#define KLU_defaults klu_l_defaults
#define KLU_free klu_l_free
#define KLU_malloc klu_l_malloc
#define KLU_realloc klu_l_realloc
#define KLU_add_size_t klu_l_add_size_t
#define KLU_mult_size_t klu_l_mult_size_t
#define KLU_symbolic klu_l_symbolic
#define KLU_numeric klu_l_numeric
#define KLU_common klu_l_common
#define BTF_order btf_l_order
#define BTF_strongcomp btf_l_strongcomp
#define AMD_order amd_l_order
#define COLAMD colamd_l
#define COLAMD_recommended colamd_l_recommended
#else
#define KLU_analyze klu_analyze
#define KLU_analyze_given klu_analyze_given
#define KLU_alloc_symbolic klu_alloc_symbolic
#define KLU_free_symbolic klu_free_symbolic
#define KLU_defaults klu_defaults
#define KLU_free klu_free
#define KLU_malloc klu_malloc
#define KLU_realloc klu_realloc
#define KLU_add_size_t klu_add_size_t
#define KLU_mult_size_t klu_mult_size_t
#define KLU_symbolic klu_symbolic
#define KLU_numeric klu_numeric
#define KLU_common klu_common
#define BTF_order btf_order
#define BTF_strongcomp btf_strongcomp
#define AMD_order amd_order
#define COLAMD colamd
#define COLAMD_recommended colamd_recommended
#endif
/* -------------------------------------------------------------------------- */
/* Numerical relop macros for correctly handling the NaN case */
/* -------------------------------------------------------------------------- */
/*
SCALAR_IS_NAN(x):
True if x is NaN. False otherwise. The commonly-existing isnan(x)
function could be used, but it's not in Kernighan & Ritchie 2nd edition
(ANSI C). It may appear in <math.h>, but I'm not certain about
portability. The expression x != x is true if and only if x is NaN,
according to the IEEE 754 floating-point standard.
SCALAR_IS_ZERO(x):
True if x is zero. False if x is nonzero, NaN, or +/- Inf.
This is (x == 0) if the compiler is IEEE 754 compliant.
SCALAR_IS_NONZERO(x):
True if x is nonzero, NaN, or +/- Inf. False if x zero.
This is (x != 0) if the compiler is IEEE 754 compliant.
SCALAR_IS_LTZERO(x):
True if x is < zero or -Inf. False if x is >= 0, NaN, or +Inf.
This is (x < 0) if the compiler is IEEE 754 compliant.
*/
/* These all work properly, according to the IEEE 754 standard ... except on */
/* a PC with windows. Works fine in Linux on the same PC... */
#define SCALAR_IS_NAN(x) ((x) != (x))
#define SCALAR_IS_ZERO(x) ((x) == 0.)
#define SCALAR_IS_NONZERO(x) ((x) != 0.)
#define SCALAR_IS_LTZERO(x) ((x) < 0.)
/* scalar absolute value macro. If x is NaN, the result is NaN: */
#define SCALAR_ABS(x) ((SCALAR_IS_LTZERO (x)) ? -(x) : (x))
/* print a scalar (avoid printing "-0" for negative zero). */
#ifdef NPRINT
#define PRINT_SCALAR(a)
#else
#define PRINT_SCALAR(a) \
{ \
if (SCALAR_IS_NONZERO (a)) \
{ \
PRINTF ((" (%g)", (a))) ; \
} \
else \
{ \
PRINTF ((" (0)")) ; \
} \
}
#endif
/* -------------------------------------------------------------------------- */
/* Real floating-point arithmetic */
/* -------------------------------------------------------------------------- */
#ifndef COMPLEX
typedef double Unit ;
#define Entry double
#define SPLIT(s) (1)
#define REAL(c) (c)
#define IMAG(c) (0.)
#define ASSIGN(c,s1,s2,p,split) { (c) = (s1)[p] ; }
#define CLEAR(c) { (c) = 0. ; }
#define CLEAR_AND_INCREMENT(p) { *p++ = 0. ; }
#define IS_NAN(a) SCALAR_IS_NAN (a)
#define IS_ZERO(a) SCALAR_IS_ZERO (a)
#define IS_NONZERO(a) SCALAR_IS_NONZERO (a)
#define SCALE_DIV(c,s) { (c) /= (s) ; }
#define SCALE_DIV_ASSIGN(a,c,s) { a = c / s ; }
#define SCALE(c,s) { (c) *= (s) ; }
#define ASSEMBLE(c,a) { (c) += (a) ; }
#define ASSEMBLE_AND_INCREMENT(c,p) { (c) += *p++ ; }
#define DECREMENT(c,a) { (c) -= (a) ; }
#define MULT(c,a,b) { (c) = (a) * (b) ; }
#define MULT_CONJ(c,a,b) { (c) = (a) * (b) ; }
#define MULT_SUB(c,a,b) { (c) -= (a) * (b) ; }
#define MULT_SUB_CONJ(c,a,b) { (c) -= (a) * (b) ; }
#define DIV(c,a,b) { (c) = (a) / (b) ; }
#define RECIPROCAL(c) { (c) = 1.0 / (c) ; }
#define DIV_CONJ(c,a,b) { (c) = (a) / (b) ; }
#define APPROX_ABS(s,a) { (s) = SCALAR_ABS (a) ; }
#define ABS(s,a) { (s) = SCALAR_ABS (a) ; }
#define PRINT_ENTRY(a) PRINT_SCALAR (a)
#define CONJ(a,x) a = x
/* for flop counts */
#define MULTSUB_FLOPS 2. /* c -= a*b */
#define DIV_FLOPS 1. /* c = a/b */
#define ABS_FLOPS 0. /* c = abs (a) */
#define ASSEMBLE_FLOPS 1. /* c += a */
#define DECREMENT_FLOPS 1. /* c -= a */
#define MULT_FLOPS 1. /* c = a*b */
#define SCALE_FLOPS 1. /* c = a/s */
#else
/* -------------------------------------------------------------------------- */
/* Complex floating-point arithmetic */
/* -------------------------------------------------------------------------- */
/*
Note: An alternative to this Double_Complex type would be to use a
struct { double r ; double i ; }. The problem with that method
(used by the Sun Performance Library, for example) is that ANSI C provides
no guarantee about the layout of a struct. It is possible that the sizeof
the struct above would be greater than 2 * sizeof (double). This would
mean that the complex BLAS could not be used. The method used here avoids
that possibility. ANSI C *does* guarantee that an array of structs has
the same size as n times the size of one struct.
The ANSI C99 version of the C language includes a "double _Complex" type.
It should be possible in that case to do the following:
#define Entry double _Complex
and remove the Double_Complex struct. The macros, below, could then be
replaced with instrinsic operators. Note that the #define Real and
#define Imag should also be removed (they only appear in this file).
For the MULT, MULT_SUB, MULT_SUB_CONJ, and MULT_CONJ macros,
the output argument c cannot be the same as any input argument.
*/
typedef struct
{
double component [2] ; /* real and imaginary parts */
} Double_Complex ;
typedef Double_Complex Unit ;
#define Entry Double_Complex
#define Real component [0]
#define Imag component [1]
/* for flop counts */
#define MULTSUB_FLOPS 8. /* c -= a*b */
#define DIV_FLOPS 9. /* c = a/b */
#define ABS_FLOPS 6. /* c = abs (a), count sqrt as one flop */
#define ASSEMBLE_FLOPS 2. /* c += a */
#define DECREMENT_FLOPS 2. /* c -= a */
#define MULT_FLOPS 6. /* c = a*b */
#define SCALE_FLOPS 2. /* c = a/s or c = a*s */
/* -------------------------------------------------------------------------- */
/* real part of c */
#define REAL(c) ((c).Real)
/* -------------------------------------------------------------------------- */
/* imag part of c */
#define IMAG(c) ((c).Imag)
/* -------------------------------------------------------------------------- */
/* Return TRUE if a complex number is in split form, FALSE if in packed form */
#define SPLIT(sz) ((sz) != (double *) NULL)
/* c = (s1) + (s2)*i, if s2 is null, then X is in "packed" format (compatible
* with Entry and ANSI C99 double _Complex type). */
/*#define ASSIGN(c,s1,s2,p,split) \
{ \
if (split) \
{ \
(c).Real = (s1)[p] ; \
(c).Imag = (s2)[p] ; \
} \
else \
{ \
(c) = ((Entry *)(s1))[p] ; \
} \
}*/
/* -------------------------------------------------------------------------- */
#define CONJ(a, x) \
{ \
a.Real = x.Real ; \
a.Imag = -x.Imag ; \
}
/* c = 0 */
#define CLEAR(c) \
{ \
(c).Real = 0. ; \
(c).Imag = 0. ; \
}
/* -------------------------------------------------------------------------- */
/* *p++ = 0 */
#define CLEAR_AND_INCREMENT(p) \
{ \
p->Real = 0. ; \
p->Imag = 0. ; \
p++ ; \
}
/* -------------------------------------------------------------------------- */
/* True if a == 0 */
#define IS_ZERO(a) \
(SCALAR_IS_ZERO ((a).Real) && SCALAR_IS_ZERO ((a).Imag))
/* -------------------------------------------------------------------------- */
/* True if a is NaN */
#define IS_NAN(a) \
(SCALAR_IS_NAN ((a).Real) || SCALAR_IS_NAN ((a).Imag))
/* -------------------------------------------------------------------------- */
/* True if a != 0 */
#define IS_NONZERO(a) \
(SCALAR_IS_NONZERO ((a).Real) || SCALAR_IS_NONZERO ((a).Imag))
/* -------------------------------------------------------------------------- */
/* a = c/s */
#define SCALE_DIV_ASSIGN(a,c,s) \
{ \
a.Real = c.Real / s ; \
a.Imag = c.Imag / s ; \
}
/* c /= s */
#define SCALE_DIV(c,s) \
{ \
(c).Real /= (s) ; \
(c).Imag /= (s) ; \
}
/* -------------------------------------------------------------------------- */
/* c *= s */
#define SCALE(c,s) \
{ \
(c).Real *= (s) ; \
(c).Imag *= (s) ; \
}
/* -------------------------------------------------------------------------- */
/* c += a */
#define ASSEMBLE(c,a) \
{ \
(c).Real += (a).Real ; \
(c).Imag += (a).Imag ; \
}
/* -------------------------------------------------------------------------- */
/* c += *p++ */
#define ASSEMBLE_AND_INCREMENT(c,p) \
{ \
(c).Real += p->Real ; \
(c).Imag += p->Imag ; \
p++ ; \
}
/* -------------------------------------------------------------------------- */
/* c -= a */
#define DECREMENT(c,a) \
{ \
(c).Real -= (a).Real ; \
(c).Imag -= (a).Imag ; \
}
/* -------------------------------------------------------------------------- */
/* c = a*b, assert because c cannot be the same as a or b */
#define MULT(c,a,b) \
{ \
ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
(c).Real = (a).Real * (b).Real - (a).Imag * (b).Imag ; \
(c).Imag = (a).Imag * (b).Real + (a).Real * (b).Imag ; \
}
/* -------------------------------------------------------------------------- */
/* c = a*conjugate(b), assert because c cannot be the same as a or b */
#define MULT_CONJ(c,a,b) \
{ \
ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
(c).Real = (a).Real * (b).Real + (a).Imag * (b).Imag ; \
(c).Imag = (a).Imag * (b).Real - (a).Real * (b).Imag ; \
}
/* -------------------------------------------------------------------------- */
/* c -= a*b, assert because c cannot be the same as a or b */
#define MULT_SUB(c,a,b) \
{ \
ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
(c).Real -= (a).Real * (b).Real - (a).Imag * (b).Imag ; \
(c).Imag -= (a).Imag * (b).Real + (a).Real * (b).Imag ; \
}
/* -------------------------------------------------------------------------- */
/* c -= a*conjugate(b), assert because c cannot be the same as a or b */
#define MULT_SUB_CONJ(c,a,b) \
{ \
ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
(c).Real -= (a).Real * (b).Real + (a).Imag * (b).Imag ; \
(c).Imag -= (a).Imag * (b).Real - (a).Real * (b).Imag ; \
}
/* -------------------------------------------------------------------------- */
/* c = a/b, be careful to avoid underflow and overflow */
#ifdef MATHWORKS
#define DIV(c,a,b) \
{ \
(void) utDivideComplex ((a).Real, (a).Imag, (b).Real, (b).Imag, \
&((c).Real), &((c).Imag)) ; \
}
#else
/* This uses ACM Algo 116, by R. L. Smith, 1962. */
/* c can be the same variable as a or b. */
/* Ignore NaN case for double relop br>=bi. */
#define DIV(c,a,b) \
{ \
double r, den, ar, ai, br, bi ; \
br = (b).Real ; \
bi = (b).Imag ; \
ar = (a).Real ; \
ai = (a).Imag ; \
if (SCALAR_ABS (br) >= SCALAR_ABS (bi)) \
{ \
r = bi / br ; \
den = br + r * bi ; \
(c).Real = (ar + ai * r) / den ; \
(c).Imag = (ai - ar * r) / den ; \
} \
else \
{ \
r = br / bi ; \
den = r * br + bi ; \
(c).Real = (ar * r + ai) / den ; \
(c).Imag = (ai * r - ar) / den ; \
} \
}
#endif
/* -------------------------------------------------------------------------- */
/* c = 1/c, be careful to avoid underflow and overflow */
/* Not used if MATHWORKS is defined. */
/* This uses ACM Algo 116, by R. L. Smith, 1962. */
/* Ignore NaN case for double relop cr>=ci. */
#define RECIPROCAL(c) \
{ \
double r, den, cr, ci ; \
cr = (c).Real ; \
ci = (c).Imag ; \
if (SCALAR_ABS (cr) >= SCALAR_ABS (ci)) \
{ \
r = ci / cr ; \
den = cr + r * ci ; \
(c).Real = 1.0 / den ; \
(c).Imag = - r / den ; \
} \
else \
{ \
r = cr / ci ; \
den = r * cr + ci ; \
(c).Real = r / den ; \
(c).Imag = - 1.0 / den ; \
} \
}
/* -------------------------------------------------------------------------- */
/* c = a/conjugate(b), be careful to avoid underflow and overflow */
#ifdef MATHWORKS
#define DIV_CONJ(c,a,b) \
{ \
(void) utDivideComplex ((a).Real, (a).Imag, (b).Real, (-(b).Imag), \
&((c).Real), &((c).Imag)) ; \
}
#else
/* This uses ACM Algo 116, by R. L. Smith, 1962. */
/* c can be the same variable as a or b. */
/* Ignore NaN case for double relop br>=bi. */
#define DIV_CONJ(c,a,b) \
{ \
double r, den, ar, ai, br, bi ; \
br = (b).Real ; \
bi = (b).Imag ; \
ar = (a).Real ; \
ai = (a).Imag ; \
if (SCALAR_ABS (br) >= SCALAR_ABS (bi)) \
{ \
r = (-bi) / br ; \
den = br - r * bi ; \
(c).Real = (ar + ai * r) / den ; \
(c).Imag = (ai - ar * r) / den ; \
} \
else \
{ \
r = br / (-bi) ; \
den = r * br - bi; \
(c).Real = (ar * r + ai) / den ; \
(c).Imag = (ai * r - ar) / den ; \
} \
}
#endif
/* -------------------------------------------------------------------------- */
/* approximate absolute value, s = |r|+|i| */
#define APPROX_ABS(s,a) \
{ \
(s) = SCALAR_ABS ((a).Real) + SCALAR_ABS ((a).Imag) ; \
}
/* -------------------------------------------------------------------------- */
/* exact absolute value, s = sqrt (a.real^2 + amag^2) */
#ifdef MATHWORKS
#define ABS(s,a) \
{ \
(s) = utFdlibm_hypot ((a).Real, (a).Imag) ; \
}
#else
/* Ignore NaN case for the double relops ar>=ai and ar+ai==ar. */
#define ABS(s,a) \
{ \
double r, ar, ai ; \
ar = SCALAR_ABS ((a).Real) ; \
ai = SCALAR_ABS ((a).Imag) ; \
if (ar >= ai) \
{ \
if (ar + ai == ar) \
{ \
(s) = ar ; \
} \
else \
{ \
r = ai / ar ; \
(s) = ar * sqrt (1.0 + r*r) ; \
} \
} \
else \
{ \
if (ai + ar == ai) \
{ \
(s) = ai ; \
} \
else \
{ \
r = ar / ai ; \
(s) = ai * sqrt (1.0 + r*r) ; \
} \
} \
}
#endif
/* -------------------------------------------------------------------------- */
/* print an entry (avoid printing "-0" for negative zero). */
#ifdef NPRINT
#define PRINT_ENTRY(a)
#else
#define PRINT_ENTRY(a) \
{ \
if (SCALAR_IS_NONZERO ((a).Real)) \
{ \
PRINTF ((" (%g", (a).Real)) ; \
} \
else \
{ \
PRINTF ((" (0")) ; \
} \
if (SCALAR_IS_LTZERO ((a).Imag)) \
{ \
PRINTF ((" - %gi)", -(a).Imag)) ; \
} \
else if (SCALAR_IS_ZERO ((a).Imag)) \
{ \
PRINTF ((" + 0i)")) ; \
} \
else \
{ \
PRINTF ((" + %gi)", (a).Imag)) ; \
} \
}
#endif
/* -------------------------------------------------------------------------- */
#endif /* #ifndef COMPLEX */
#endif

771
src/maths/KLU/klusmp.c Normal file
View File

@ -0,0 +1,771 @@
/*
* Spice3 COMPATIBILITY MODULE
*
* Author: Advising professor:
* Kenneth S. Kundert Alberto Sangiovanni-Vincentelli
* UC Berkeley
*
* This module contains routines that make Sparse1.3 a direct
* replacement for the SMP sparse matrix package in Spice3c1 or Spice3d1.
* Sparse1.3 is in general a faster and more robust package than SMP.
* These advantages become significant on large circuits.
*
* >>> User accessible functions contained in this file:
* SMPaddElt
* SMPmakeElt
* SMPcClear
* SMPclear
* SMPcLUfac
* SMPluFac
* SMPcReorder
* SMPreorder
* SMPcaSolve
* SMPcSolve
* SMPsolve
* SMPmatSize
* SMPnewMatrix
* SMPdestroy
* SMPpreOrder
* SMPprint
* SMPgetError
* SMPcProdDiag
* LoadGmin
* SMPfindElt
* SMPcombine
* SMPcCombine
*/
/*
* To replace SMP with Sparse, rename the file spSpice3.h to
* spMatrix.h and place Sparse in a subdirectory of SPICE called
* `sparse'. Then on UNIX compile Sparse by executing `make spice'.
* If not on UNIX, after compiling Sparse and creating the sparse.a
* archive, compile this file (spSMP.c) and spSMP.o to the archive,
* then copy sparse.a into the SPICE main directory and rename it
* SMP.a. Finally link SPICE.
*
* To be compatible with SPICE, the following Sparse compiler options
* (in spConfig.h) should be set as shown below:
*
* EXPANDABLE YES
* TRANSLATE NO
* INITIALIZE NO or YES, YES for use with test prog.
* DIAGONAL_PIVOTING YES
* MODIFIED_MARKOWITZ NO
* DELETE NO
* STRIP NO
* MODIFIED_NODAL YES
* QUAD_ELEMENT NO
* TRANSPOSE YES
* SCALING NO
* DOCUMENTATION YES
* MULTIPLICATION NO
* DETERMINANT YES
* STABILITY NO
* CONDITION NO
* PSEUDOCONDITION NO
* DEBUG YES
*
* spREAL double
*/
/*
* Revision and copyright information.
*
* Copyright (c) 1985,86,87,88,89,90
* by Kenneth S. Kundert and the University of California.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and supporting
* documentation and that the authors and the University of California
* are properly credited. The authors and the University of California
* make no representations as to the suitability of this software for
* any purpose. It is provided `as is', without express or implied warranty.
*/
/*
* IMPORTS
*
* >>> Import descriptions:
* spMatrix.h
* Sparse macros and declarations.
* SMPdefs.h
* Spice3's matrix macro definitions.
*/
#include "ngspice/config.h"
#include <assert.h>
#include <stdio.h>
#include <math.h>
#include "ngspice/spmatrix.h"
#include "../sparse/spdefs.h"
#include "ngspice/smpdefs.h"
#if defined (_MSC_VER)
extern double scalbn(double, int);
#define logb _logb
extern double logb(double);
#endif
static void LoadGmin_CSC (double **diag, int n, double Gmin) ;
static void LoadGmin (SMPmatrix *eMatrix, double Gmin) ;
void
SMPmatrix_CSC (SMPmatrix *Matrix)
{
spMatrix_CSC (Matrix->SPmatrix, Matrix->CKTkluAp, Matrix->CKTkluAi, Matrix->CKTkluAx,
Matrix->CKTkluAx_Complex, Matrix->CKTkluN, Matrix->CKTbindStruct, Matrix->CKTdiag_CSC) ;
return ;
}
void
SMPnnz (SMPmatrix *Matrix)
{
Matrix->CKTklunz = Matrix->SPmatrix->Elements ;
return ;
}
/*
* SMPaddElt()
*/
int
SMPaddElt (SMPmatrix *Matrix, int Row, int Col, double Value)
{
*spGetElement (Matrix->SPmatrix, Row, Col) = Value ;
return spError (Matrix->SPmatrix) ;
}
/*
* SMPmakeElt()
*/
double *
SMPmakeElt (SMPmatrix *Matrix, int Row, int Col)
{
return spGetElement (Matrix->SPmatrix, Row, Col) ;
}
/*
* SMPcClear()
*/
void
SMPcClear (SMPmatrix *Matrix)
{
int i ;
if (Matrix->CKTkluMODE)
{
spClear (Matrix->SPmatrix) ;
if (Matrix->CKTkluAx_Complex != NULL)
{
for (i = 0 ; i < 2 * Matrix->CKTklunz ; i++)
Matrix->CKTkluAx_Complex [i] = 0 ;
}
} else {
spClear (Matrix->SPmatrix) ;
}
}
/*
* SMPclear()
*/
void
SMPclear (SMPmatrix *Matrix)
{
int i ;
if (Matrix->CKTkluMODE)
{
spClear (Matrix->SPmatrix) ;
if (Matrix->CKTkluAx != NULL)
{
for (i = 0 ; i < Matrix->CKTklunz ; i++)
Matrix->CKTkluAx [i] = 0 ;
}
} else {
spClear (Matrix->SPmatrix) ;
}
}
#define NG_IGNORE(x) (void)x
/*
* SMPcLUfac()
*/
/*ARGSUSED*/
int
SMPcLUfac (SMPmatrix *Matrix, double PivTol)
{
int ret ;
NG_IGNORE (PivTol) ;
if (Matrix->CKTkluMODE)
{
spSetComplex (Matrix->SPmatrix) ;
ret = klu_z_refactor (Matrix->CKTkluAp, Matrix->CKTkluAi, Matrix->CKTkluAx_Complex,
Matrix->CKTkluSymbolic, Matrix->CKTkluNumeric, Matrix->CKTkluCommon) ;
return (!ret) ;
} else {
spSetComplex (Matrix->SPmatrix) ;
return spFactor (Matrix->SPmatrix) ;
}
}
/*
* SMPluFac()
*/
/*ARGSUSED*/
int
SMPluFac (SMPmatrix *Matrix, double PivTol, double Gmin)
{
int ret ;
NG_IGNORE (PivTol) ;
if (Matrix->CKTkluMODE)
{
spSetReal (Matrix->SPmatrix) ;
LoadGmin_CSC (Matrix->CKTdiag_CSC, Matrix->CKTkluN, Gmin) ;
ret = klu_refactor (Matrix->CKTkluAp, Matrix->CKTkluAi, Matrix->CKTkluAx,
Matrix->CKTkluSymbolic, Matrix->CKTkluNumeric, Matrix->CKTkluCommon) ;
return (!ret) ;
// if (ret == 1)
// return 0 ;
// else if (ret == 0)
// return (E_SINGULAR) ;
// else {
// fprintf (stderr, "KLU Error in re-factor!") ;
// return 1 ;
// }
} else {
spSetReal (Matrix->SPmatrix) ;
LoadGmin (Matrix, Gmin) ;
return spFactor (Matrix->SPmatrix) ;
}
}
/*
* SMPcReorder()
*/
int
SMPcReorder (SMPmatrix *Matrix, double PivTol, double PivRel, int *NumSwaps)
{
if (Matrix->CKTkluMODE)
{
*NumSwaps = 1 ;
spSetComplex (Matrix->SPmatrix) ;
if (Matrix->CKTkluNumeric != NULL)
{
klu_z_free_numeric (&(Matrix->CKTkluNumeric), Matrix->CKTkluCommon) ;
Matrix->CKTkluNumeric = klu_z_factor (Matrix->CKTkluAp, Matrix->CKTkluAi, Matrix->CKTkluAx_Complex, Matrix->CKTkluSymbolic, Matrix->CKTkluCommon) ;
} else
Matrix->CKTkluNumeric = klu_z_factor (Matrix->CKTkluAp, Matrix->CKTkluAi, Matrix->CKTkluAx_Complex, Matrix->CKTkluSymbolic, Matrix->CKTkluCommon) ;
if (Matrix->CKTkluNumeric == NULL)
return 1 ;
else
return 0 ;
} else {
*NumSwaps = 1 ;
spSetComplex (Matrix->SPmatrix) ;
return spOrderAndFactor (Matrix->SPmatrix, NULL, (spREAL)PivRel, (spREAL)PivTol, YES) ;
}
}
/*
* SMPreorder()
*/
int
SMPreorder (SMPmatrix *Matrix, double PivTol, double PivRel, double Gmin)
{
if (Matrix->CKTkluMODE)
{
spSetReal (Matrix->SPmatrix) ;
LoadGmin_CSC (Matrix->CKTdiag_CSC, Matrix->CKTkluN, Gmin) ;
if (Matrix->CKTkluNumeric != NULL)
{
klu_free_numeric (&(Matrix->CKTkluNumeric), Matrix->CKTkluCommon) ;
Matrix->CKTkluNumeric = klu_factor (Matrix->CKTkluAp, Matrix->CKTkluAi, Matrix->CKTkluAx, Matrix->CKTkluSymbolic, Matrix->CKTkluCommon) ;
} else
Matrix->CKTkluNumeric = klu_factor (Matrix->CKTkluAp, Matrix->CKTkluAi, Matrix->CKTkluAx, Matrix->CKTkluSymbolic, Matrix->CKTkluCommon) ;
if (Matrix->CKTkluNumeric == NULL)
return 1 ;
else
return 0 ;
} else {
spSetReal (Matrix->SPmatrix) ;
LoadGmin (Matrix, Gmin) ;
return spOrderAndFactor (Matrix->SPmatrix, NULL, (spREAL)PivRel, (spREAL)PivTol, YES) ;
}
}
/*
* SMPcaSolve()
*/
void
SMPcaSolve (SMPmatrix *Matrix, double RHS[], double iRHS[], double Spare[], double iSpare[])
{
printf ("SMPcaSolve\n") ;
NG_IGNORE (iSpare) ;
NG_IGNORE (Spare) ;
spSolveTransposed (Matrix->SPmatrix, RHS, RHS, iRHS, iRHS) ;
}
/*
* SMPcSolve()
*/
void
SMPcSolve (SMPmatrix *Matrix, double RHS[], double iRHS[], double Spare[], double iSpare[])
{
int ret, i, *pExtOrder ;
NG_IGNORE (iSpare) ;
NG_IGNORE (Spare) ;
if (Matrix->CKTkluMODE)
{
pExtOrder = &Matrix->SPmatrix->IntToExtRowMap [Matrix->CKTkluN] ;
for (i = 2 * Matrix->CKTkluN - 1 ; i > 0 ; i -= 2)
{
Matrix->CKTkluIntermediate_Complex [i] = RHS [*(pExtOrder)] ;
Matrix->CKTkluIntermediate_Complex [i - 1] = iRHS [*(pExtOrder--)] ;
}
ret = klu_z_solve (Matrix->CKTkluSymbolic, Matrix->CKTkluNumeric, Matrix->CKTkluN, 1, Matrix->CKTkluIntermediate_Complex, Matrix->CKTkluCommon) ;
pExtOrder = &Matrix->SPmatrix->IntToExtColMap [Matrix->CKTkluN] ;
for (i = 2 * Matrix->CKTkluN - 1 ; i > 0 ; i -= 2)
{
RHS [*(pExtOrder)] = Matrix->CKTkluIntermediate_Complex [i] ;
iRHS [*(pExtOrder--)] = Matrix->CKTkluIntermediate_Complex [i - 1] ;
}
} else {
spSolve (Matrix->SPmatrix, RHS, RHS, iRHS, iRHS) ;
}
}
/*
* SMPsolve()
*/
void
SMPsolve (SMPmatrix *Matrix, double RHS[], double Spare[])
{
int ret, i, *pExtOrder ;
NG_IGNORE (Spare) ;
if (Matrix->CKTkluMODE) {
pExtOrder = &Matrix->SPmatrix->IntToExtRowMap [Matrix->CKTkluN] ;
for (i = Matrix->CKTkluN - 1 ; i >= 0 ; i--)
Matrix->CKTkluIntermediate [i] = RHS [*(pExtOrder--)] ;
ret = klu_solve (Matrix->CKTkluSymbolic, Matrix->CKTkluNumeric, Matrix->CKTkluN, 1, Matrix->CKTkluIntermediate, Matrix->CKTkluCommon) ;
pExtOrder = &Matrix->SPmatrix->IntToExtColMap [Matrix->CKTkluN] ;
for (i = Matrix->CKTkluN - 1 ; i >= 0 ; i--)
RHS [*(pExtOrder--)] = Matrix->CKTkluIntermediate [i] ;
} else {
spSolve (Matrix->SPmatrix, RHS, RHS, NULL, NULL) ;
}
}
/*
* SMPmatSize()
*/
int
SMPmatSize (SMPmatrix *Matrix)
{
return spGetSize (Matrix->SPmatrix, 1) ;
}
/*
* SMPnewMatrix()
*/
int
SMPnewMatrix (SMPmatrix *Matrix)
{
int Error ;
Matrix->SPmatrix = spCreate (0, 1, &Error) ;
return Error ;
}
/*
* SMPdestroy()
*/
void
SMPdestroy (SMPmatrix *Matrix)
{
if (Matrix->CKTkluMODE)
{
printf("Destroy\n") ;
spDestroy (Matrix->SPmatrix) ;
klu_free_numeric (&(Matrix->CKTkluNumeric), Matrix->CKTkluCommon) ;
klu_free_symbolic (&(Matrix->CKTkluSymbolic), Matrix->CKTkluCommon) ;
free (Matrix->CKTkluAp) ;
free (Matrix->CKTkluAi) ;
free (Matrix->CKTkluAx) ;
free (Matrix->CKTdiag_CSC) ;
free (Matrix->CKTkluIntermediate) ;
free (Matrix->CKTkluIntermediate_Complex) ;
} else {
spDestroy (Matrix->SPmatrix) ;
}
}
/*
* SMPpreOrder()
*/
int
SMPpreOrder (SMPmatrix *Matrix)
{
if (Matrix->CKTkluMODE)
{
Matrix->CKTkluSymbolic = klu_analyze (Matrix->CKTkluN, Matrix->CKTkluAp, Matrix->CKTkluAi, Matrix->CKTkluCommon) ;
return 0 ;
} else {
spMNA_Preorder (Matrix->SPmatrix) ;
return spError (Matrix->SPmatrix) ;
}
}
/*
* SMPprintRHS()
*/
void
SMPprintRHS (SMPmatrix *Matrix, char *Filename, RealVector RHS, RealVector iRHS)
{
if (!Matrix->CKTkluMODE)
spFileVector (Matrix->SPmatrix, Filename, RHS, iRHS) ;
}
/*
* SMPprint()
*/
void
SMPprint (SMPmatrix *Matrix, char *Filename)
{
if (!Matrix->CKTkluMODE)
{
if (Filename)
spFileMatrix (Matrix->SPmatrix, Filename, "Circuit Matrix", 0, 1, 1) ;
else
spPrint (Matrix->SPmatrix, 0, 1, 1) ;
}
}
/*
* SMPgetError()
*/
void
SMPgetError (SMPmatrix *Matrix, int *Col, int *Row)
{
if (Matrix->CKTkluMODE)
{
*Row = Matrix->SPmatrix->IntToExtRowMap [Matrix->CKTkluCommon->singular_col] ;
*Col = Matrix->SPmatrix->IntToExtColMap [Matrix->CKTkluCommon->singular_col] ;
} else {
spWhereSingular (Matrix->SPmatrix, Row, Col) ;
}
}
/*
* SMPcProdDiag()
* note: obsolete for Spice3d2 and later
*/
int
SMPcProdDiag (SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent)
{
spDeterminant (Matrix->SPmatrix, pExponent, &(pMantissa->real), &(pMantissa->imag)) ;
return spError (Matrix->SPmatrix) ;
}
/*
* SMPcDProd()
*/
int
SMPcDProd (SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent)
{
double re, im, x, y, z;
int p;
spDeterminant (Matrix->SPmatrix, &p, &re, &im) ;
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
#endif
#ifndef M_LN10
#define M_LN10 2.30258509299404568402
#endif
#ifdef debug_print
printf ("Determinant 10: (%20g,%20g)^%d\n", re, im, p) ;
#endif
/* Convert base 10 numbers to base 2 numbers, for comparison */
y = p * M_LN10 / M_LN2;
x = (int) y;
y -= x;
/* ASSERT
* x = integral part of exponent, y = fraction part of exponent
*/
/* Fold in the fractional part */
#ifdef debug_print
printf (" ** base10 -> base2 int = %g, frac = %20g\n", x, y) ;
#endif
z = pow (2.0, y) ;
re *= z ;
im *= z ;
#ifdef debug_print
printf (" ** multiplier = %20g\n", z) ;
#endif
/* Re-normalize (re or im may be > 2.0 or both < 1.0 */
if (re != 0.0)
{
y = logb (re) ;
if (im != 0.0)
z = logb (im) ;
else
z = 0 ;
} else if (im != 0.0) {
z = logb (im) ;
y = 0 ;
} else {
/* Singular */
/*printf("10 -> singular\n");*/
y = 0 ;
z = 0 ;
}
#ifdef debug_print
printf (" ** renormalize changes = %g,%g\n", y, z) ;
#endif
if (y < z)
y = z ;
*pExponent = (int)(x + y) ;
x = scalbn (re, (int) -y) ;
z = scalbn (im, (int) -y) ;
#ifdef debug_print
printf (" ** values are: re %g, im %g, y %g, re' %g, im' %g\n", re, im, y, x, z) ;
#endif
pMantissa->real = scalbn (re, (int) -y) ;
pMantissa->imag = scalbn (im, (int) -y) ;
#ifdef debug_print
printf ("Determinant 10->2: (%20g,%20g)^%d\n", pMantissa->real, pMantissa->imag, *pExponent) ;
#endif
return spError (Matrix->SPmatrix) ;
}
/*
* The following routines need internal knowledge of the Sparse data
* structures.
*/
/*
* LOAD GMIN
*
* This routine adds Gmin to each diagonal element. Because Gmin is
* added to the current diagonal, which may bear little relation to
* what the outside world thinks is a diagonal, and because the
* elements that are diagonals may change after calling spOrderAndFactor,
* use of this routine is not recommended. It is included here simply
* for compatibility with Spice3.
*/
static void
LoadGmin_CSC (double **diag, int n, double Gmin)
{
int i ;
if (Gmin != 0.0)
for (i = 0 ; i < n ; i++)
if (diag [i] != NULL)
*(diag [i]) += Gmin ;
}
static void
LoadGmin (SMPmatrix *eMatrix, double Gmin)
{
MatrixPtr Matrix = eMatrix->SPmatrix ;
int I ;
ArrayOfElementPtrs Diag ;
ElementPtr diag ;
/* Begin `LoadGmin'. */
assert (IS_SPARSE (Matrix)) ;
if (Gmin != 0.0) {
Diag = Matrix->Diag ;
for (I = Matrix->Size ; I > 0 ; I--)
{
if ((diag = Diag [I]) != NULL)
diag->Real += Gmin ;
}
}
return ;
}
/*
* FIND ELEMENT
*
* This routine finds an element in the matrix by row and column number.
* If the element exists, a pointer to it is returned. If not, then NULL
* is returned unless the CreateIfMissing flag is TRUE, in which case a
* pointer to the new element is returned.
*/
SMPelement *
SMPfindElt (SMPmatrix *eMatrix, int Row, int Col, int CreateIfMissing)
{
MatrixPtr Matrix = eMatrix->SPmatrix ;
ElementPtr Element ;
/* Begin `SMPfindElt'. */
assert (IS_SPARSE (Matrix)) ;
Row = Matrix->ExtToIntRowMap [Row] ;
Col = Matrix->ExtToIntColMap [Col] ;
Element = Matrix->FirstInCol [Col] ;
Element = spcFindElementInCol (Matrix, &Element, Row, Col, CreateIfMissing) ;
return (SMPelement *)Element ;
}
/* XXX The following should probably be implemented in spUtils */
/*
* SMPcZeroCol()
*/
int
SMPcZeroCol (SMPmatrix *eMatrix, int Col)
{
MatrixPtr Matrix = eMatrix->SPmatrix ;
ElementPtr Element ;
Col = Matrix->ExtToIntColMap [Col] ;
for (Element = Matrix->FirstInCol [Col] ; Element != NULL ; Element = Element->NextInCol)
{
Element->Real = 0.0 ;
Element->Imag = 0.0 ;
}
return spError (Matrix) ;
}
/*
* SMPcAddCol()
*/
int
SMPcAddCol (SMPmatrix *eMatrix, int Accum_Col, int Addend_Col)
{
MatrixPtr Matrix = eMatrix->SPmatrix ;
ElementPtr Accum, Addend, *Prev ;
Accum_Col = Matrix->ExtToIntColMap [Accum_Col] ;
Addend_Col = Matrix->ExtToIntColMap [Addend_Col] ;
Addend = Matrix->FirstInCol [Addend_Col] ;
Prev = &Matrix->FirstInCol [Accum_Col] ;
Accum = *Prev;
while (Addend != NULL)
{
while (Accum && Accum->Row < Addend->Row)
{
Prev = &Accum->NextInCol ;
Accum = *Prev ;
}
if (!Accum || Accum->Row > Addend->Row)
{
Accum = spcCreateElement (Matrix, Addend->Row, Accum_Col, Prev, 0) ;
}
Accum->Real += Addend->Real ;
Accum->Imag += Addend->Imag ;
Addend = Addend->NextInCol ;
}
return spError (Matrix) ;
}
/*
* SMPzeroRow()
*/
int
SMPzeroRow (SMPmatrix *eMatrix, int Row)
{
MatrixPtr Matrix = eMatrix->SPmatrix ;
ElementPtr Element ;
Row = Matrix->ExtToIntColMap [Row] ;
if (Matrix->RowsLinked == NO)
spcLinkRows (Matrix) ;
if (Matrix->PreviousMatrixWasComplex || Matrix->Complex)
{
for (Element = Matrix->FirstInRow[Row] ; Element != NULL; Element = Element->NextInRow)
{
Element->Real = 0.0 ;
Element->Imag = 0.0 ;
}
} else {
for (Element = Matrix->FirstInRow [Row] ; Element != NULL ; Element = Element->NextInRow)
{
Element->Real = 0.0 ;
}
}
return spError (Matrix) ;
}
#ifdef PARALLEL_ARCH
/*
* SMPcombine()
*/
void
SMPcombine (SMPmatrix *Matrix, double RHS[], double Spare[])
{
spSetReal (Matrix->SPmatrix) ;
spCombine (Matrix->SPmatrix, RHS, Spare, NULL, NULL) ;
}
/*
* SMPcCombine()
*/
void
SMPcCombine (SMPmatrix *Matrix, double RHS[], double Spare[], double iRHS[], double iSpare[])
{
spSetComplex (Matrix->SPmatrix) ;
spCombine (Matrix->SPmatrix, RHS, Spare, iRHS, iSpare) ;
}
#endif /* PARALLEL_ARCH */

View File

@ -1,6 +1,10 @@
## Process this file with automake
SUBDIRS = cmaths ni sparse poly deriv misc fft
DIST_SUBDIRS = cmaths ni sparse poly deriv misc fft
DIST_SUBDIRS = cmaths ni sparse poly deriv misc fft KLU
if KLU_WANTED
SUBDIRS += KLU
endif
MAINTAINERCLEANFILES = Makefile.in

View File

@ -16,6 +16,9 @@ Author: 1985 Thomas L. Quarles
#include "ngspice/sperror.h"
#include "ngspice/smpdefs.h"
#ifdef KLU
#include "ngspice/klu.h"
#endif
int
NIinit(CKTcircuit *ckt)
@ -24,6 +27,29 @@ NIinit(CKTcircuit *ckt)
/* a concession to Ken Kundert's sparse matrix package - SMP doesn't need this*/
int Error;
#endif /* SPARSE */
/* Allocation of the new SMPmatrix structure - Francesco Lannutti (2012-02) */
ckt->CKTmatrix = TMALLOC (SMPmatrix, 1) ;
#ifdef KLU
ckt->CKTmatrix->CKTkluCommon = TMALLOC (klu_common, 1) ;
ckt->CKTmatrix->CKTkluSymbolic = NULL ;
ckt->CKTmatrix->CKTkluNumeric = NULL ;
ckt->CKTmatrix->CKTkluAp = NULL ;
ckt->CKTmatrix->CKTkluAi = NULL ;
ckt->CKTmatrix->CKTkluAx = NULL ;
ckt->CKTmatrix->CKTkluMatrixIsComplex = CKTkluMatrixReal ;
ckt->CKTmatrix->CKTkluIntermediate = NULL ;
ckt->CKTmatrix->CKTkluIntermediate_Complex = NULL ;
ckt->CKTmatrix->CKTbindStruct = NULL ;
ckt->CKTmatrix->CKTdiag_CSC = NULL ;
ckt->CKTmatrix->CKTkluN = 0 ;
ckt->CKTmatrix->CKTklunz = 0 ;
ckt->CKTmatrix->CKTkluMODE = ckt->CKTkluMODE ; /* TO BE SUBSTITUTED WITH THE HEURISTICS */
klu_defaults (ckt->CKTmatrix->CKTkluCommon) ;
#endif
ckt->CKTniState = NIUNINITIALIZED;
return(SMPnewMatrix( &(ckt->CKTmatrix) ) );
return (SMPnewMatrix (ckt->CKTmatrix));
}

View File

@ -2,7 +2,7 @@
noinst_LTLIBRARIES = libsparse.la
libsparse_la_SOURCES = \
libsparse_la_SOURCES = \
spalloc.c \
spbuild.c \
spconfig.h \
@ -15,7 +15,9 @@ libsparse_la_SOURCES = \
sputils.c
if KLU_WANTED
libsparse_la_SOURCES += spCSC.c
endif
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include
AM_CFLAGS = $(STATIC)

145
src/maths/sparse/spCSC.c Normal file
View File

@ -0,0 +1,145 @@
/* Sparse Matrix to CSC Matrix Conversion Routines
* Including Dump Routines
*
* Author: Francesco Lannutti 2011-2012
*
* Instructions:
* spMatrix_CSC_dump and spRHS_CSC_dump are the dump routines;
* insert them in a point in your code after that the Sparse Matrix
* is filled in to dump the whole matrix in the CSC format.
* To solve correctly the resulting CSC linear system, it's crucial
* to perform another inversion of the Solution Vector following this code:
*
* pExtOrder = IntToExtColMap [n] ;
* for (i = n - 1 ; i >= 0 ; i--)
* RHS [*(pExtOrder--)] = Intermediate [i] ;
*/
/* Includes */
#include "ngspice/spmatrix.h"
#include "spdefs.h"
/* Body */
int
WriteCol_original (MatrixPtr Matrix, int Col, spREAL *CSC_Element, spREAL *CSC_Element_Complex, int *CSC_Row, BindElement *BindSparseCSC, spREAL **diag)
{
int i ;
ElementPtr current ;
i = 0 ;
current = Matrix->FirstInCol [Col] ;
while (current != NULL) {
BindSparseCSC [i].Sparse = (double *)current ;
BindSparseCSC [i].CSC = &(CSC_Element [i]) ;
BindSparseCSC [i].CSC_Complex = &(CSC_Element_Complex [2 * i]) ;
CSC_Row [i] = (current->Row) - 1 ;
if (CSC_Row [i] == Col - 1)
diag [0] = &(CSC_Element [i]) ;
i++ ;
current = current->NextInCol ;
}
return i ;
}
int
WriteCol_original_dump (MatrixPtr Matrix, int Col, spREAL *CSC_Element, int *CSC_Row)
{
int i ;
ElementPtr current ;
i = 0 ;
current = Matrix->FirstInCol [Col] ;
while (current != NULL) {
CSC_Element [i] = current->Real ;
CSC_Row [i] = (current->Row) - 1 ;
i++ ;
current = current->NextInCol ;
}
return i ;
}
void
spMatrix_CSC (MatrixPtr Matrix, int *Ap, int *Ai, double *Ax, double *Ax_Complex, int n, BindElement *BindSparseCSC, double **diag)
{
int offset, i ;
offset = 0 ;
Ap[0] = offset ;
for (i = 1 ; i <= n ; i++) {
offset += WriteCol_original (Matrix, i, (spREAL *)(Ax + offset), (spREAL *)(Ax_Complex + 2 * offset),
(int *)(Ai + offset), BindSparseCSC + offset, (spREAL **)(diag + (i - 1))) ;
Ap[i] = offset ;
}
}
void
spMatrix_CSC_dump (MatrixPtr Matrix, char *CSC_output)
{
FILE *output ;
int offset, i, j, *Ap, *Ai, n, nz ;
double *Ax ;
n = spGetSize (Matrix, 1) ;
nz = Matrix->Elements ;
Ap = (int *) SP_MALLOC (int, n + 1) ;
Ai = (int *) SP_MALLOC (int, nz) ;
Ax = (double *) SP_MALLOC (double, nz) ;
offset = 0 ;
Ap[0] = offset ;
for (i = 1 ; i <= n ; i++) {
offset += WriteCol_original_dump (Matrix, i, (spREAL *)(Ax + offset), (int *)(Ai + offset)) ;
Ap[i] = offset ;
}
output = fopen (CSC_output, "w") ;
fprintf (output, "%%%%MatrixMarket matrix coordinate real general\n") ;
fprintf (output, "%%-------------------------------------------------------------------------------\n") ;
fprintf (output, "%% Transient Matrix Dump\n%% Family: ISCAS Circuit\n") ;
fprintf (output, "%%-------------------------------------------------------------------------------\n") ;
fprintf (output, "%d %d %d\n", n, n, offset) ;
for (i = 0 ; i < n ; i++)
for (j = Ap [i] ; j < Ap [i + 1] ; j++)
fprintf (output, "%d %d %-.9g\n", Ai [j] + 1, i + 1, Ax [j]) ;
fclose (output) ;
output = fopen ("IntToExtColMap.txt", "w") ;
for (i = 1 ; i <= n ; i++)
fprintf (output, "%d\n", Matrix->IntToExtColMap [i]) ;
fclose (output) ;
SP_FREE (Ap) ;
SP_FREE (Ai) ;
SP_FREE (Ax) ;
}
void
spRHS_CSC_dump (RealNumber *RHS, char *CSC_output_b, MatrixPtr Matrix)
{
FILE *output ;
int i, n, *pExtOrder ;
double *Intermediate ;
n = spGetSize (Matrix, 1) ;
Intermediate = (double *) SP_MALLOC (double, n) ;
pExtOrder = &Matrix->IntToExtRowMap [n] ;
for (i = n - 1 ; i >= 0 ; i--)
Intermediate [i] = RHS [*(pExtOrder--)] ;
output = fopen (CSC_output_b, "w") ;
fprintf (output, "%%%%MatrixMarket matrix array real general\n") ;
fprintf (output, "%%-------------------------------------------------------------------------------\n") ;
fprintf (output, "%% Transient RHS Vector Dump\n%% Family: ISCAS Circuit\n") ;
fprintf (output, "%%-------------------------------------------------------------------------------\n") ;
fprintf (output, "%d %d\n", n, 1) ;
for (i = 1 ; i < n + 1 ; i++)
fprintf (output, "%-.9g\n", Intermediate [i]) ;
fclose (output) ;
SP_FREE (Intermediate) ;
}

View File

@ -106,8 +106,7 @@ extern double scalbn(double, int);
extern double logb(double);
#endif
static void LoadGmin(SMPmatrix *Matrix, double Gmin);
static void LoadGmin(SMPmatrix *eMatrix, double Gmin);
/*
* SMPaddElt()
@ -115,8 +114,8 @@ static void LoadGmin(SMPmatrix *Matrix, double Gmin);
int
SMPaddElt(SMPmatrix *Matrix, int Row, int Col, double Value)
{
*spGetElement( Matrix, Row, Col ) = Value;
return spError( Matrix );
*spGetElement( Matrix->SPmatrix, Row, Col ) = Value;
return spError( Matrix->SPmatrix );
}
/*
@ -125,7 +124,7 @@ SMPaddElt(SMPmatrix *Matrix, int Row, int Col, double Value)
double *
SMPmakeElt(SMPmatrix *Matrix, int Row, int Col)
{
return spGetElement( Matrix, Row, Col );
return spGetElement( Matrix->SPmatrix, Row, Col );
}
/*
@ -134,7 +133,7 @@ SMPmakeElt(SMPmatrix *Matrix, int Row, int Col)
void
SMPcClear(SMPmatrix *Matrix)
{
spClear( Matrix );
spClear( Matrix->SPmatrix );
}
/*
@ -143,7 +142,7 @@ SMPcClear(SMPmatrix *Matrix)
void
SMPclear(SMPmatrix *Matrix)
{
spClear( Matrix );
spClear( Matrix->SPmatrix );
}
#define NG_IGNORE(x) (void)x
@ -157,8 +156,8 @@ SMPcLUfac(SMPmatrix *Matrix, double PivTol)
{
NG_IGNORE(PivTol);
spSetComplex( Matrix );
return spFactor( Matrix );
spSetComplex( Matrix->SPmatrix );
return spFactor( Matrix->SPmatrix );
}
/*
@ -169,9 +168,9 @@ int
SMPluFac(SMPmatrix *Matrix, double PivTol, double Gmin)
{
NG_IGNORE(PivTol);
spSetReal( Matrix );
spSetReal( Matrix->SPmatrix );
LoadGmin( Matrix, Gmin );
return spFactor( Matrix );
return spFactor( Matrix->SPmatrix );
}
/*
@ -182,8 +181,8 @@ SMPcReorder(SMPmatrix *Matrix, double PivTol, double PivRel,
int *NumSwaps)
{
*NumSwaps = 1;
spSetComplex( Matrix );
return spOrderAndFactor( Matrix, NULL,
spSetComplex( Matrix->SPmatrix );
return spOrderAndFactor( Matrix->SPmatrix, NULL,
PivRel, PivTol, YES );
}
@ -193,9 +192,9 @@ SMPcReorder(SMPmatrix *Matrix, double PivTol, double PivRel,
int
SMPreorder(SMPmatrix *Matrix, double PivTol, double PivRel, double Gmin)
{
spSetReal( Matrix );
spSetReal( Matrix->SPmatrix );
LoadGmin( Matrix, Gmin );
return spOrderAndFactor( Matrix, NULL,
return spOrderAndFactor( Matrix->SPmatrix, NULL,
PivRel, PivTol, YES );
}
@ -209,7 +208,7 @@ SMPcaSolve(SMPmatrix *Matrix, double RHS[], double iRHS[],
NG_IGNORE(iSpare);
NG_IGNORE(Spare);
spSolveTransposed( Matrix, RHS, RHS, iRHS, iRHS );
spSolveTransposed( Matrix->SPmatrix, RHS, RHS, iRHS, iRHS );
}
/*
@ -222,7 +221,7 @@ SMPcSolve(SMPmatrix *Matrix, double RHS[], double iRHS[],
NG_IGNORE(iSpare);
NG_IGNORE(Spare);
spSolve( Matrix, RHS, RHS, iRHS, iRHS );
spSolve( Matrix->SPmatrix, RHS, RHS, iRHS, iRHS );
}
/*
@ -233,7 +232,7 @@ SMPsolve(SMPmatrix *Matrix, double RHS[], double Spare[])
{
NG_IGNORE(Spare);
spSolve( Matrix, RHS, RHS, NULL, NULL );
spSolve( Matrix->SPmatrix, RHS, RHS, NULL, NULL );
}
/*
@ -242,17 +241,17 @@ SMPsolve(SMPmatrix *Matrix, double RHS[], double Spare[])
int
SMPmatSize(SMPmatrix *Matrix)
{
return spGetSize( Matrix, 1 );
return spGetSize( Matrix->SPmatrix, 1 );
}
/*
* SMPnewMatrix()
*/
int
SMPnewMatrix(SMPmatrix **pMatrix)
SMPnewMatrix(SMPmatrix *Matrix)
{
int Error;
*pMatrix = spCreate( 0, 1, &Error );
Matrix->SPmatrix = spCreate( 0, 1, &Error );
return Error;
}
@ -262,7 +261,7 @@ SMPnewMatrix(SMPmatrix **pMatrix)
void
SMPdestroy(SMPmatrix *Matrix)
{
spDestroy( Matrix );
spDestroy( Matrix->SPmatrix );
}
/*
@ -271,18 +270,18 @@ SMPdestroy(SMPmatrix *Matrix)
int
SMPpreOrder(SMPmatrix *Matrix)
{
spMNA_Preorder( Matrix );
return spError( Matrix );
spMNA_Preorder( Matrix->SPmatrix );
return spError( Matrix->SPmatrix );
}
/*
* SMPprint()
* SMPprintRHS()
*/
void
SMPprintRHS(SMPmatrix *Matrix, char *Filename, RealVector RHS, RealVector iRHS)
{
spFileVector( Matrix, Filename, RHS, iRHS );
spFileVector( Matrix->SPmatrix, Filename, RHS, iRHS );
}
/*
@ -293,9 +292,9 @@ void
SMPprint(SMPmatrix *Matrix, char *Filename)
{
if (Filename)
spFileMatrix(Matrix, Filename, "Circuit Matrix", 0, 1, 1 );
spFileMatrix(Matrix->SPmatrix, Filename, "Circuit Matrix", 0, 1, 1 );
else
spPrint( Matrix, 0, 1, 1 );
spPrint( Matrix->SPmatrix, 0, 1, 1 );
}
/*
@ -304,7 +303,7 @@ SMPprint(SMPmatrix *Matrix, char *Filename)
void
SMPgetError(SMPmatrix *Matrix, int *Col, int *Row)
{
spWhereSingular( Matrix, Row, Col );
spWhereSingular( Matrix->SPmatrix, Row, Col );
}
/*
@ -314,9 +313,9 @@ SMPgetError(SMPmatrix *Matrix, int *Col, int *Row)
int
SMPcProdDiag(SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent)
{
spDeterminant( Matrix, pExponent, &(pMantissa->real),
spDeterminant ( Matrix->SPmatrix, pExponent, &(pMantissa->real),
&(pMantissa->imag) );
return spError( Matrix );
return spError( Matrix->SPmatrix );
}
/*
@ -328,7 +327,7 @@ SMPcDProd(SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent)
double re, im, x, y, z;
int p;
spDeterminant( Matrix, &p, &re, &im);
spDeterminant( Matrix->SPmatrix, &p, &re, &im);
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
@ -398,7 +397,7 @@ SMPcDProd(SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent)
printf("Determinant 10->2: (%20g,%20g)^%d\n", pMantissa->real,
pMantissa->imag, *pExponent);
#endif
return spError( Matrix );
return spError( Matrix->SPmatrix );
}
@ -420,8 +419,9 @@ SMPcDProd(SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent)
*/
static void
LoadGmin(SMPmatrix *Matrix, double Gmin)
LoadGmin(SMPmatrix *eMatrix, double Gmin)
{
MatrixPtr Matrix = eMatrix->SPmatrix;
int I;
ArrayOfElementPtrs Diag;
ElementPtr diag;
@ -452,8 +452,9 @@ LoadGmin(SMPmatrix *Matrix, double Gmin)
*/
SMPelement *
SMPfindElt(SMPmatrix *Matrix, int Row, int Col, int CreateIfMissing)
SMPfindElt(SMPmatrix *eMatrix, int Row, int Col, int CreateIfMissing)
{
MatrixPtr Matrix = eMatrix->SPmatrix;
ElementPtr Element;
/* Begin `SMPfindElt'. */
@ -462,7 +463,7 @@ SMPfindElt(SMPmatrix *Matrix, int Row, int Col, int CreateIfMissing)
Col = Matrix->ExtToIntColMap[Col];
Element = Matrix->FirstInCol[Col];
Element = spcFindElementInCol(Matrix, &Element, Row, Col, CreateIfMissing);
return Element;
return (SMPelement *)Element;
}
/* XXX The following should probably be implemented in spUtils */
@ -471,8 +472,9 @@ SMPfindElt(SMPmatrix *Matrix, int Row, int Col, int CreateIfMissing)
* SMPcZeroCol()
*/
int
SMPcZeroCol(SMPmatrix *Matrix, int Col)
SMPcZeroCol(SMPmatrix *eMatrix, int Col)
{
MatrixPtr Matrix = eMatrix->SPmatrix;
ElementPtr Element;
Col = Matrix->ExtToIntColMap[Col];
@ -492,8 +494,9 @@ SMPcZeroCol(SMPmatrix *Matrix, int Col)
* SMPcAddCol()
*/
int
SMPcAddCol(SMPmatrix *Matrix, int Accum_Col, int Addend_Col)
SMPcAddCol(SMPmatrix *eMatrix, int Accum_Col, int Addend_Col)
{
MatrixPtr Matrix = eMatrix->SPmatrix;
ElementPtr Accum, Addend, *Prev;
Accum_Col = Matrix->ExtToIntColMap[Accum_Col];
@ -523,8 +526,9 @@ SMPcAddCol(SMPmatrix *Matrix, int Accum_Col, int Addend_Col)
* SMPzeroRow()
*/
int
SMPzeroRow(SMPmatrix *Matrix, int Row)
SMPzeroRow(SMPmatrix *eMatrix, int Row)
{
MatrixPtr Matrix = eMatrix->SPmatrix;
ElementPtr Element;
Row = Matrix->ExtToIntColMap[Row];

View File

@ -241,6 +241,23 @@ ACan(CKTcircuit *ckt, int restart)
ckt->CKTcurrentAnalysis = DOING_AC;
#ifdef KLU
int i ;
if (ckt->CKTmatrix->CKTkluMODE)
{
/* Conversion from Real Matrix to Complex Matrix */
if (!ckt->CKTmatrix->CKTkluMatrixIsComplex)
{
for (i = 0 ; i < DEVmaxnum ; i++)
if (DEVices [i] && DEVices [i]->DEVbindCSCComplex && ckt->CKThead [i])
DEVices [i]->DEVbindCSCComplex (ckt->CKThead [i], ckt) ;
ckt->CKTmatrix->CKTkluMatrixIsComplex = CKTkluMatrixComplex ;
}
}
#endif
/* main loop through all scheduled frequencies */
while (freq <= job->ACstopFreq + freqTol) {
if(SPfrontEnd->IFpauseTest()) {
@ -252,6 +269,19 @@ ACan(CKTcircuit *ckt, int restart)
/* Update opertating point, if variable 'hertz' is given */
if (ckt->CKTvarHertz) {
#ifdef KLU
if (ckt->CKTmatrix->CKTkluMODE)
{
/* Conversion from Complex Matrix to Real Matrix */
for (i = 0 ; i < DEVmaxnum ; i++)
if (DEVices [i] && DEVices [i]->DEVbindCSCComplexToReal && ckt->CKThead [i])
DEVices [i]->DEVbindCSCComplexToReal (ckt->CKThead [i], ckt) ;
ckt->CKTmatrix->CKTkluMatrixIsComplex = CKTkluMatrixReal ;
}
#endif
#ifdef XSPICE
/* Call EVTop if event-driven instances exist */
@ -280,6 +310,19 @@ ACan(CKTcircuit *ckt, int restart)
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG;
error = CKTload(ckt);
if(error) return(error);
#ifdef KLU
if (ckt->CKTmatrix->CKTkluMODE)
{
/* Conversion from Real Matrix to Complex Matrix */
for (i = 0 ; i < DEVmaxnum ; i++)
if (DEVices [i] && DEVices [i]->DEVbindCSCComplex && ckt->CKThead [i])
DEVices [i]->DEVbindCSCComplex (ckt->CKThead [i], ckt) ;
ckt->CKTmatrix->CKTkluMatrixIsComplex = CKTkluMatrixComplex ;
}
#endif
}
ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODEAC;
@ -379,6 +422,19 @@ endsweep:
SPfrontEnd->OUTendPlot (acPlot);
acPlot = NULL;
UPDATE_STATS(0);
#ifdef KLU
if (ckt->CKTmatrix->CKTkluMODE)
{
/* Conversion from Complex Matrix to Real Matrix */
for (i = 0 ; i < DEVmaxnum ; i++)
if (DEVices [i] && DEVices [i]->DEVbindCSCComplexToReal && ckt->CKThead [i])
DEVices [i]->DEVbindCSCComplexToReal (ckt->CKThead [i], ckt) ;
ckt->CKTmatrix->CKTkluMatrixIsComplex = CKTkluMatrixReal ;
}
#endif
return(0);
}

View File

@ -18,7 +18,14 @@ Author: 1985 Thomas L. Quarles
#include "ngspice/cktdefs.h"
#include "ngspice/spmatrix.h"
#ifdef KLU
#include "ngspice/klu.h"
#endif
/* Francesco Lannutti
* If ACCT is called before NIinit, the new SMPmatrix structure is not allocated
* so the control must be performed on the CKTmatrix pointer to the SMPmatrix structure
*/
/* ARGSUSED */
int
@ -33,21 +40,35 @@ CKTacct(CKTcircuit *ckt, JOB *anal, int which, IFvalue *val)
break;
case OPT_ORIGNZ:
if ( ckt->CKTmatrix != NULL ) {
val->iValue = spOriginalCount(ckt->CKTmatrix);
val->iValue = spOriginalCount(ckt->CKTmatrix->SPmatrix);
} else {
val->iValue = 0;
}
break;
case OPT_FILLNZ:
if ( ckt->CKTmatrix != NULL ) {
val->iValue = spFillinCount(ckt->CKTmatrix);
#ifdef KLU
if (ckt->CKTmatrix->CKTkluMODE)
val->iValue = ckt->CKTmatrix->CKTkluNumeric->lnz + ckt->CKTmatrix->CKTkluNumeric->unz + ckt->CKTmatrix->CKTkluNumeric->nzoff - ckt->CKTmatrix->CKTklunz ;
else
val->iValue = spFillinCount(ckt->CKTmatrix->SPmatrix);
#else
val->iValue = spFillinCount(ckt->CKTmatrix->SPmatrix);
#endif
} else {
val->iValue = 0;
}
break;
case OPT_TOTALNZ:
if ( ckt->CKTmatrix != NULL ) {
val->iValue = spElementCount(ckt->CKTmatrix);
#ifdef KLU
if (ckt->CKTmatrix->CKTkluMODE)
val->iValue = ckt->CKTmatrix->CKTkluNumeric->lnz + ckt->CKTmatrix->CKTkluNumeric->unz + ckt->CKTmatrix->CKTkluNumeric->nzoff ;
else
val->iValue = spElementCount(ckt->CKTmatrix->SPmatrix);
#else
val->iValue = spElementCount(ckt->CKTmatrix->SPmatrix);
#endif
} else {
val->iValue = 0;
}

View File

@ -103,6 +103,11 @@ CKTdoJob(CKTcircuit *ckt, int reset, TSKtask *task)
ckt->CKTtroubleNode = 0;
ckt->CKTtroubleElt = NULL;
ckt->CKTnoopac = task->TSKnoopac && ckt->CKTisLinear;
#ifdef KLU
ckt->CKTkluMODE = task->TSKkluMODE ;
#endif
#ifdef NEWTRUNC
ckt->CKTlteReltol = task->TSKlteReltol;
ckt->CKTlteAbstol = task->TSKlteAbstol;

View File

@ -72,6 +72,11 @@ CKTnewTask(CKTcircuit *ckt, TSKtask **taskPtr, IFuid taskName, TSKtask **defPtr)
tsk->TSKabsDv = def->TSKabsDv;
tsk->TSKrelDv = def->TSKrelDv;
tsk->TSKnoopac = def->TSKnoopac;
#ifdef KLU
tsk->TSKkluMODE = def->TSKkluMODE ;
#endif
#ifdef NEWTRUNC
tsk->TSKlteReltol = def->TSKlteReltol;
tsk->TSKlteAbstol = def->TSKlteAbstol;
@ -119,6 +124,10 @@ CKTnewTask(CKTcircuit *ckt, TSKtask **taskPtr, IFuid taskName, TSKtask **defPtr)
tsk->TSKabsDv = 0.5;
tsk->TSKrelDv = 2.0;
#ifdef KLU
tsk->TSKkluMODE = CKTkluON ;
#endif
#if (1) /*CDHW*/
}
#endif

View File

@ -55,7 +55,7 @@ static double inc_freq(double freq, int type, double step_size);
* For each element/parameter in the test list:
* construct the perturbation matrix
* Solve for the sensitivities:
* delta_E = Y^-1 (delta_Y E - delta_I)
* delta_E = Y^-1 (delta_Y->SPmatrix E - delta_I)
* save results
*/
@ -71,7 +71,8 @@ int sens_sens(CKTcircuit *ckt, int restart)
static double freq;
static int nfreqs;
static int i;
static SMPmatrix *delta_Y = NULL, *Y;
static SMPmatrix *delta_Y = NULL;
static MatrixFrame *Y;
static double step_size;
double *E, *iE;
IFvalue value, nvalue;
@ -89,7 +90,9 @@ int sens_sens(CKTcircuit *ckt, int restart)
int type;
double *saved_rhs = 0,
*saved_irhs = 0;
SMPmatrix *saved_matrix = 0;
MatrixFrame *saved_matrix = 0;
delta_Y = TMALLOC(SMPmatrix, 1);
#ifndef notdef
#ifdef notdef
@ -139,10 +142,10 @@ int sens_sens(CKTcircuit *ckt, int restart)
if (error)
return error;
size = spGetSize(ckt->CKTmatrix, 1);
size = spGetSize (ckt->CKTmatrix->SPmatrix, 1) ;
/* Create the perturbation matrix */
delta_Y = spCreate(size, 1, &error);
delta_Y->SPmatrix = spCreate(size, 1, &error);
if (error)
return error;
@ -181,7 +184,9 @@ int sens_sens(CKTcircuit *ckt, int restart)
sg->ptable[sg->param].keyword);
}
SPfrontEnd->IFnewUid (ckt, output_names + k, NULL, namebuf, UID_OTHER, NULL);
SPfrontEnd->IFnewUid (ckt,
output_names + k, NULL,
namebuf, UID_OTHER, NULL);
k += 1;
}
@ -190,14 +195,16 @@ int sens_sens(CKTcircuit *ckt, int restart)
freq_name = NULL;
} else {
type = IF_COMPLEX;
SPfrontEnd->IFnewUid (ckt, &freq_name, NULL, "frequency", UID_OTHER, NULL);
SPfrontEnd->IFnewUid (ckt,
&freq_name, NULL,
"frequency", UID_OTHER, NULL);
}
error = SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob,
ckt->CKTcurJob->JOBname,
freq_name, IF_REAL,
num_vars, output_names, type,
&sen_data);
error = SPfrontEnd->OUTpBeginPlot (
ckt, ckt->CKTcurJob,
ckt->CKTcurJob->JOBname,
freq_name, IF_REAL,
num_vars, output_names, type, &sen_data);
if (error)
return error;
@ -209,7 +216,8 @@ int sens_sens(CKTcircuit *ckt, int restart)
output_values = NULL;
output_cvalues = NEWN(IFcomplex, num_vars);
if (job->step_type != SENS_LINEAR)
SPfrontEnd->OUTattributes (sen_data, NULL, OUT_SCALE_LOG, NULL);
SPfrontEnd->OUTattributes (sen_data,
NULL, OUT_SCALE_LOG, NULL);
}
@ -231,12 +239,12 @@ int sens_sens(CKTcircuit *ckt, int restart)
bypass = ckt->CKTbypass;
ckt->CKTbypass = 0;
/* CKTop solves into CKTrhs and CKTmatrix,
/* CKTop solves into CKTrhs and CKTmatrix->SPmatrix,
* CKTirhs is hopefully zero (fresh allocated ?) */
E = ckt->CKTrhs;
iE = ckt->CKTirhs;
Y = ckt->CKTmatrix;
Y = ckt->CKTmatrix->SPmatrix;
#ifdef ASDEBUG
DEBUG(1) {
@ -279,7 +287,7 @@ int sens_sens(CKTcircuit *ckt, int restart)
if (error)
return error;
/* XXX ckt->CKTmatrix = Y; */
/* XXX ckt->CKTmatrix->SPmatrix = Y; */
error = CKTsetup(ckt);
if (error)
@ -308,17 +316,17 @@ int sens_sens(CKTcircuit *ckt, int restart)
}
#endif
/* NIacIter solves into CKTrhsOld, CKTirhsOld and CKTmatrix */
/* NIacIter solves into CKTrhsOld, CKTirhsOld and CKTmatrix->SPmatrix */
E = ckt->CKTrhsOld;
iE = ckt->CKTirhsOld;
Y = ckt->CKTmatrix;
Y = ckt->CKTmatrix->SPmatrix;
}
/* Use a different vector & matrix */
save_context(ckt->CKTrhs, saved_rhs);
save_context(ckt->CKTirhs, saved_irhs);
save_context(ckt->CKTmatrix, saved_matrix);
save_context(ckt->CKTmatrix->SPmatrix, saved_matrix);
ckt->CKTrhs = delta_I;
ckt->CKTirhs = delta_iI;
@ -351,7 +359,7 @@ int sens_sens(CKTcircuit *ckt, int restart)
}
#endif
spClear(delta_Y);
spClear(delta_Y->SPmatrix);
for (j = 0; j < size; j++) {
delta_I[j] = 0.0;
@ -394,7 +402,7 @@ int sens_sens(CKTcircuit *ckt, int restart)
#ifdef ASDEBUG
DEBUG(2) {
printf("Effect of device:\n");
spPrint(delta_Y, 0, 1, 1);
spPrint(delta_Y->SPmatrix, 0, 1, 1);
printf("LHS:\n");
for (j = 0; j < size; j++)
printf("%d: %g, %g\n", j,
@ -418,7 +426,7 @@ int sens_sens(CKTcircuit *ckt, int restart)
if (error && error != E_BADPARM)
return error;
spConstMult(delta_Y, -1.0);
spConstMult(delta_Y->SPmatrix, -1.0);
for (j = 0; j < size; j++) {
delta_I[j] *= -1.0;
delta_iI[j] *= -1.0;
@ -427,7 +435,7 @@ int sens_sens(CKTcircuit *ckt, int restart)
#ifdef ASDEBUG
DEBUG(2) {
printf("Effect of negating matrix:\n");
spPrint(delta_Y, 0, 1, 1);
spPrint(delta_Y->SPmatrix, 0, 1, 1);
for (j = 0; j < size; j++)
printf("%d: %g, %g\n", j,
delta_I[j], delta_iI[j]);
@ -453,7 +461,7 @@ int sens_sens(CKTcircuit *ckt, int restart)
#ifdef ASDEBUG
DEBUG(2) {
printf("Effect of changing the parameter:\n");
spPrint(delta_Y, 0, 1, 1);
spPrint(delta_Y->SPmatrix, 0, 1, 1);
for (j = 0; j < size; j++)
printf("%d: %g, %g\n", j,
delta_I[j], delta_iI[j]);
@ -477,17 +485,17 @@ int sens_sens(CKTcircuit *ckt, int restart)
#endif
/* delta_Y E */
spMultiply(delta_Y, delta_I_delta_Y, E,
spMultiply(delta_Y->SPmatrix, delta_I_delta_Y, E,
delta_iI_delta_Y, iE);
#ifdef ASDEBUG
DEBUG(2)
for (j = 0; j < size; j++)
printf("delta_Y * E [%d] = %20.15g\n",
printf("delta_Y->SPmatrix * E [%d] = %20.15g\n",
j, delta_I_delta_Y[j]);
#endif
/* delta_I - delta_Y E */
/* delta_I - delta_Y->SPmatrix E */
for (j = 0; j < size; j++) {
delta_I[j] -= delta_I_delta_Y[j];
delta_iI[j] -= delta_iI_delta_Y[j];
@ -538,21 +546,24 @@ int sens_sens(CKTcircuit *ckt, int restart)
if (is_dc) {
if (job->output_volt)
output_values[n] =
delta_I [job->output_pos->number]
- delta_I [job->output_neg->number];
output_values[n] = delta_I
[job->output_pos->number]
- delta_I
[job->output_neg->number];
else {
output_values[n] = delta_I[branch_eq];
}
output_values[n] /= delta_var;
} else {
if (job->output_volt) {
output_cvalues[n].real =
delta_I [job->output_pos->number]
- delta_I [job->output_neg->number];
output_cvalues[n].imag =
delta_iI [job->output_pos->number]
- delta_iI [job->output_neg->number];
output_cvalues[n].real = delta_I
[job->output_pos->number]
- delta_I
[job->output_neg->number];
output_cvalues[n].imag = delta_iI
[job->output_pos->number]
- delta_iI
[job->output_neg->number];
} else {
output_cvalues[n].real =
delta_I[branch_eq];
@ -569,7 +580,7 @@ int sens_sens(CKTcircuit *ckt, int restart)
release_context(ckt->CKTrhs, saved_rhs);
release_context(ckt->CKTirhs, saved_irhs);
release_context(ckt->CKTmatrix, saved_matrix);
release_context(ckt->CKTmatrix->SPmatrix, saved_matrix);
if (is_dc)
nvalue.v.vec.rVec = output_values;
@ -594,9 +605,9 @@ int sens_sens(CKTcircuit *ckt, int restart)
release_context(ckt->CKTrhs, saved_rhs);
release_context(ckt->CKTirhs, saved_irhs);
release_context(ckt->CKTmatrix, saved_matrix);
release_context(ckt->CKTmatrix->SPmatrix, saved_matrix);
spDestroy(delta_Y);
spDestroy(delta_Y->SPmatrix);
FREE(delta_I);
FREE(delta_iI);
@ -620,7 +631,7 @@ int sens_sens(CKTcircuit *ckt, int restart)
double
inc_freq(double freq, int type, double step_size)
{
if (type != SENS_LINEAR)
if (type != LINEAR)
freq *= step_size;
else
freq += step_size;

View File

@ -26,6 +26,20 @@ int nthreads;
return(E_NOMEM);\
}
#ifdef KLU
#include <stdlib.h>
static
int
BindCompare (const void *a, const void *b)
{
BindElement *A, *B ;
A = (BindElement *)a ;
B = (BindElement *)b ;
return ((int)(A->Sparse - B->Sparse)) ;
}
#endif
int
CKTsetup(CKTcircuit *ckt)
@ -79,6 +93,53 @@ CKTsetup(CKTcircuit *ckt)
if(error) return(error);
}
}
#ifdef KLU
if (ckt->CKTmatrix->CKTkluMODE)
SMPnnz (ckt->CKTmatrix) ;
#endif
#ifdef KLU
if (ckt->CKTmatrix->CKTkluMODE)
{
fprintf (stderr, "Using KLU as Direct Linear Solver\n") ;
int i ;
int n = SMPmatSize (ckt->CKTmatrix) ;
ckt->CKTmatrix->CKTkluN = n ;
int nz = ckt->CKTmatrix->CKTklunz ;
ckt->CKTmatrix->CKTkluAp = TMALLOC (int, n + 1) ;
ckt->CKTmatrix->CKTkluAi = TMALLOC (int, nz) ;
ckt->CKTmatrix->CKTkluAx = TMALLOC (double, nz) ;
ckt->CKTmatrix->CKTkluIntermediate = TMALLOC (double, n) ;
ckt->CKTmatrix->CKTbindStruct = TMALLOC (BindElement, nz) ;
ckt->CKTmatrix->CKTdiag_CSC = TMALLOC (double *, n) ;
/* Complex Stuff needed for AC Analysis */
ckt->CKTmatrix->CKTkluAx_Complex = TMALLOC (double, 2 * nz) ;
ckt->CKTmatrix->CKTkluIntermediate_Complex = TMALLOC (double, 2 * n) ;
/* Binding Table from Sparse to CSC Format Creation */
SMPmatrix_CSC (ckt->CKTmatrix) ;
/* Binding Table Sorting */
qsort (ckt->CKTmatrix->CKTbindStruct, (size_t)nz, sizeof(BindElement), BindCompare) ;
/* KLU Pointers Assignment */
for (i = 0 ; i < DEVmaxnum ; i++)
if (DEVices [i] && DEVices [i]->DEVbindCSC && ckt->CKThead [i])
DEVices [i]->DEVbindCSC (ckt->CKThead [i], ckt) ;
ckt->CKTmatrix->CKTkluMatrixIsComplex = CKTkluMatrixReal ;
} else {
fprintf (stderr, "Using SPARSE 1.3 as Direct Linear Solver\n") ;
}
#endif
for(i=0;i<=MAX(2,ckt->CKTmaxOrder)+1;i++) { /* dctran needs 3 states as minimum */
CKALLOC(ckt->CKTstates[i],ckt->CKTnumStates,double);
}

View File

@ -161,6 +161,13 @@ CKTsetOpt(CKTcircuit *ckt, JOB *anal, int opt, IFvalue *val)
case OPT_NOOPAC:
task->TSKnoopac = (val->iValue != 0);
break;
#ifdef KLU
case OPT_SPARSE:
task->TSKkluMODE = (val->iValue == 0) ;
break ;
#endif
/* gtri - begin - wbk - add new options */
#ifdef XSPICE
case OPT_EVT_MAX_OP_ALTER:
@ -313,7 +320,13 @@ static IFparm OPTtbl[] = {
{ "reldv", OPT_RELDV, IF_SET|IF_REAL,
"Maximum relative iter-iter node voltage change" },
{ "noopac", OPT_NOOPAC, IF_SET|IF_FLAG,
"No op calculation in ac if circuit is linear" }
"No op calculation in ac if circuit is linear" },
#ifdef KLU
{ "sparse", OPT_SPARSE, IF_SET|IF_FLAG,
"Set SPARSE 1.3 as Direct Linear Solver" }
#endif
};
int OPTcount = NUMELEMS(OPTtbl);

View File

@ -74,7 +74,14 @@ SPICEdev ASRCinfo = {
/* DEVacct */ NULL,
#endif
/* DEVinstSize */ &ASRCiSize,
/* DEVmodSize */ &ASRCmSize
/* DEVmodSize */ &ASRCmSize,
#ifdef KLU
/* DEVbindCSC */ NULL,
/* DEVbindCSCComplex */ NULL,
/* DEVbindCSCComplexToReal */ NULL,
#endif
};

View File

@ -36,6 +36,9 @@ libbjt_la_SOURCES = \
bjttrunc.c
if KLU_WANTED
libbjt_la_SOURCES += bjtbindCSC.c
endif
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include
AM_CFLAGS = $(STATIC)

View File

@ -0,0 +1,407 @@
/**********
Author: 2013 Francesco Lannutti
**********/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "bjtdefs.h"
#include "ngspice/sperror.h"
#include <stdlib.h>
static
int
BindCompare (const void *a, const void *b)
{
BindElement *A, *B ;
A = (BindElement *)a ;
B = (BindElement *)b ;
return ((int)(A->Sparse - B->Sparse)) ;
}
int
BJTbindCSC (GENmodel *inModel, CKTcircuit *ckt)
{
BJTmodel *model = (BJTmodel *)inModel ;
BJTinstance *here ;
double *i ;
BindElement *matched, *BindStruct ;
size_t nz ;
BindStruct = ckt->CKTmatrix->CKTbindStruct ;
nz = (size_t)ckt->CKTmatrix->CKTklunz ;
/* loop through all the BJT models */
for ( ; model != NULL ; model = model->BJTnextModel)
{
/* loop through all the instances of the model */
for (here = model->BJTinstances ; here != NULL ; here = here->BJTnextInstance)
{
if ((here->BJTcolNode != 0) && (here->BJTcolPrimeNode != 0))
{
i = here->BJTcolColPrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTcolColPrimeStructPtr = matched ;
here->BJTcolColPrimePtr = matched->CSC ;
}
if ((here->BJTbaseNode != 0) && (here->BJTbasePrimeNode != 0))
{
i = here->BJTbaseBasePrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTbaseBasePrimeStructPtr = matched ;
here->BJTbaseBasePrimePtr = matched->CSC ;
}
if ((here->BJTemitNode != 0) && (here->BJTemitPrimeNode != 0))
{
i = here->BJTemitEmitPrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTemitEmitPrimeStructPtr = matched ;
here->BJTemitEmitPrimePtr = matched->CSC ;
}
if ((here->BJTcolPrimeNode != 0) && (here->BJTcolNode != 0))
{
i = here->BJTcolPrimeColPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTcolPrimeColStructPtr = matched ;
here->BJTcolPrimeColPtr = matched->CSC ;
}
if ((here->BJTcolPrimeNode != 0) && (here->BJTbasePrimeNode != 0))
{
i = here->BJTcolPrimeBasePrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTcolPrimeBasePrimeStructPtr = matched ;
here->BJTcolPrimeBasePrimePtr = matched->CSC ;
}
if ((here->BJTcolPrimeNode != 0) && (here->BJTemitPrimeNode != 0))
{
i = here->BJTcolPrimeEmitPrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTcolPrimeEmitPrimeStructPtr = matched ;
here->BJTcolPrimeEmitPrimePtr = matched->CSC ;
}
if ((here->BJTbasePrimeNode != 0) && (here->BJTbaseNode != 0))
{
i = here->BJTbasePrimeBasePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTbasePrimeBaseStructPtr = matched ;
here->BJTbasePrimeBasePtr = matched->CSC ;
}
if ((here->BJTbasePrimeNode != 0) && (here->BJTcolPrimeNode != 0))
{
i = here->BJTbasePrimeColPrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTbasePrimeColPrimeStructPtr = matched ;
here->BJTbasePrimeColPrimePtr = matched->CSC ;
}
if ((here->BJTbasePrimeNode != 0) && (here->BJTemitPrimeNode != 0))
{
i = here->BJTbasePrimeEmitPrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTbasePrimeEmitPrimeStructPtr = matched ;
here->BJTbasePrimeEmitPrimePtr = matched->CSC ;
}
if ((here->BJTemitPrimeNode != 0) && (here->BJTemitNode != 0))
{
i = here->BJTemitPrimeEmitPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTemitPrimeEmitStructPtr = matched ;
here->BJTemitPrimeEmitPtr = matched->CSC ;
}
if ((here->BJTemitPrimeNode != 0) && (here->BJTcolPrimeNode != 0))
{
i = here->BJTemitPrimeColPrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTemitPrimeColPrimeStructPtr = matched ;
here->BJTemitPrimeColPrimePtr = matched->CSC ;
}
if ((here->BJTemitPrimeNode != 0) && (here->BJTbasePrimeNode != 0))
{
i = here->BJTemitPrimeBasePrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTemitPrimeBasePrimeStructPtr = matched ;
here->BJTemitPrimeBasePrimePtr = matched->CSC ;
}
if ((here->BJTcolNode != 0) && (here->BJTcolNode != 0))
{
i = here->BJTcolColPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTcolColStructPtr = matched ;
here->BJTcolColPtr = matched->CSC ;
}
if ((here->BJTbaseNode != 0) && (here->BJTbaseNode != 0))
{
i = here->BJTbaseBasePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTbaseBaseStructPtr = matched ;
here->BJTbaseBasePtr = matched->CSC ;
}
if ((here->BJTemitNode != 0) && (here->BJTemitNode != 0))
{
i = here->BJTemitEmitPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTemitEmitStructPtr = matched ;
here->BJTemitEmitPtr = matched->CSC ;
}
if ((here->BJTcolPrimeNode != 0) && (here->BJTcolPrimeNode != 0))
{
i = here->BJTcolPrimeColPrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTcolPrimeColPrimeStructPtr = matched ;
here->BJTcolPrimeColPrimePtr = matched->CSC ;
}
if ((here->BJTbasePrimeNode != 0) && (here->BJTbasePrimeNode != 0))
{
i = here->BJTbasePrimeBasePrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTbasePrimeBasePrimeStructPtr = matched ;
here->BJTbasePrimeBasePrimePtr = matched->CSC ;
}
if ((here->BJTemitPrimeNode != 0) && (here->BJTemitPrimeNode != 0))
{
i = here->BJTemitPrimeEmitPrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTemitPrimeEmitPrimeStructPtr = matched ;
here->BJTemitPrimeEmitPrimePtr = matched->CSC ;
}
if ((here->BJTsubstNode != 0) && (here->BJTsubstNode != 0))
{
i = here->BJTsubstSubstPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTsubstSubstStructPtr = matched ;
here->BJTsubstSubstPtr = matched->CSC ;
}
if ((here->BJTsubstConNode != 0) && (here->BJTsubstNode != 0))
{
i = here->BJTsubstConSubstPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTsubstConSubstStructPtr = matched ;
here->BJTsubstConSubstPtr = matched->CSC ;
}
if ((here->BJTsubstNode != 0) && (here->BJTsubstConNode != 0))
{
i = here->BJTsubstSubstConPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTsubstSubstConStructPtr = matched ;
here->BJTsubstSubstConPtr = matched->CSC ;
}
if ((here->BJTbaseNode != 0) && (here->BJTcolPrimeNode != 0))
{
i = here->BJTbaseColPrimePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTbaseColPrimeStructPtr = matched ;
here->BJTbaseColPrimePtr = matched->CSC ;
}
if ((here->BJTcolPrimeNode != 0) && (here->BJTbaseNode != 0))
{
i = here->BJTcolPrimeBasePtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->BJTcolPrimeBaseStructPtr = matched ;
here->BJTcolPrimeBasePtr = matched->CSC ;
}
}
}
return (OK) ;
}
int
BJTbindCSCComplex (GENmodel *inModel, CKTcircuit *ckt)
{
BJTmodel *model = (BJTmodel *)inModel ;
BJTinstance *here ;
NG_IGNORE (ckt) ;
/* loop through all the BJT models */
for ( ; model != NULL ; model = model->BJTnextModel)
{
/* loop through all the instances of the model */
for (here = model->BJTinstances ; here != NULL ; here = here->BJTnextInstance)
{
if ((here->BJTcolNode != 0) && (here->BJTcolPrimeNode != 0))
here->BJTcolColPrimePtr = here->BJTcolColPrimeStructPtr->CSC_Complex ;
if ((here->BJTbaseNode != 0) && (here->BJTbasePrimeNode != 0))
here->BJTbaseBasePrimePtr = here->BJTbaseBasePrimeStructPtr->CSC_Complex ;
if ((here->BJTemitNode != 0) && (here->BJTemitPrimeNode != 0))
here->BJTemitEmitPrimePtr = here->BJTemitEmitPrimeStructPtr->CSC_Complex ;
if ((here->BJTcolPrimeNode != 0) && (here->BJTcolNode != 0))
here->BJTcolPrimeColPtr = here->BJTcolPrimeColStructPtr->CSC_Complex ;
if ((here->BJTcolPrimeNode != 0) && (here->BJTbasePrimeNode != 0))
here->BJTcolPrimeBasePrimePtr = here->BJTcolPrimeBasePrimeStructPtr->CSC_Complex ;
if ((here->BJTcolPrimeNode != 0) && (here->BJTemitPrimeNode != 0))
here->BJTcolPrimeEmitPrimePtr = here->BJTcolPrimeEmitPrimeStructPtr->CSC_Complex ;
if ((here->BJTbasePrimeNode != 0) && (here->BJTbaseNode != 0))
here->BJTbasePrimeBasePtr = here->BJTbasePrimeBaseStructPtr->CSC_Complex ;
if ((here->BJTbasePrimeNode != 0) && (here->BJTcolPrimeNode != 0))
here->BJTbasePrimeColPrimePtr = here->BJTbasePrimeColPrimeStructPtr->CSC_Complex ;
if ((here->BJTbasePrimeNode != 0) && (here->BJTemitPrimeNode != 0))
here->BJTbasePrimeEmitPrimePtr = here->BJTbasePrimeEmitPrimeStructPtr->CSC_Complex ;
if ((here->BJTemitPrimeNode != 0) && (here->BJTemitNode != 0))
here->BJTemitPrimeEmitPtr = here->BJTemitPrimeEmitStructPtr->CSC_Complex ;
if ((here->BJTemitPrimeNode != 0) && (here->BJTcolPrimeNode != 0))
here->BJTemitPrimeColPrimePtr = here->BJTemitPrimeColPrimeStructPtr->CSC_Complex ;
if ((here->BJTemitPrimeNode != 0) && (here->BJTbasePrimeNode != 0))
here->BJTemitPrimeBasePrimePtr = here->BJTemitPrimeBasePrimeStructPtr->CSC_Complex ;
if ((here->BJTcolNode != 0) && (here->BJTcolNode != 0))
here->BJTcolColPtr = here->BJTcolColStructPtr->CSC_Complex ;
if ((here->BJTbaseNode != 0) && (here->BJTbaseNode != 0))
here->BJTbaseBasePtr = here->BJTbaseBaseStructPtr->CSC_Complex ;
if ((here->BJTemitNode != 0) && (here->BJTemitNode != 0))
here->BJTemitEmitPtr = here->BJTemitEmitStructPtr->CSC_Complex ;
if ((here->BJTcolPrimeNode != 0) && (here->BJTcolPrimeNode != 0))
here->BJTcolPrimeColPrimePtr = here->BJTcolPrimeColPrimeStructPtr->CSC_Complex ;
if ((here->BJTbasePrimeNode != 0) && (here->BJTbasePrimeNode != 0))
here->BJTbasePrimeBasePrimePtr = here->BJTbasePrimeBasePrimeStructPtr->CSC_Complex ;
if ((here->BJTemitPrimeNode != 0) && (here->BJTemitPrimeNode != 0))
here->BJTemitPrimeEmitPrimePtr = here->BJTemitPrimeEmitPrimeStructPtr->CSC_Complex ;
if ((here->BJTsubstNode != 0) && (here->BJTsubstNode != 0))
here->BJTsubstSubstPtr = here->BJTsubstSubstStructPtr->CSC_Complex ;
if ((here->BJTsubstConNode != 0) && (here->BJTsubstNode != 0))
here->BJTsubstConSubstPtr = here->BJTsubstConSubstStructPtr->CSC_Complex ;
if ((here->BJTsubstNode != 0) && (here->BJTsubstConNode != 0))
here->BJTsubstSubstConPtr = here->BJTsubstSubstConStructPtr->CSC_Complex ;
if ((here->BJTbaseNode != 0) && (here->BJTcolPrimeNode != 0))
here->BJTbaseColPrimePtr = here->BJTbaseColPrimeStructPtr->CSC_Complex ;
if ((here->BJTcolPrimeNode != 0) && (here->BJTbaseNode != 0))
here->BJTcolPrimeBasePtr = here->BJTcolPrimeBaseStructPtr->CSC_Complex ;
}
}
return (OK) ;
}
int
BJTbindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt)
{
BJTmodel *model = (BJTmodel *)inModel ;
BJTinstance *here ;
NG_IGNORE (ckt) ;
/* loop through all the BJT models */
for ( ; model != NULL ; model = model->BJTnextModel)
{
/* loop through all the instances of the model */
for (here = model->BJTinstances ; here != NULL ; here = here->BJTnextInstance)
{
if ((here->BJTcolNode != 0) && (here->BJTcolPrimeNode != 0))
here->BJTcolColPrimePtr = here->BJTcolColPrimeStructPtr->CSC ;
if ((here->BJTbaseNode != 0) && (here->BJTbasePrimeNode != 0))
here->BJTbaseBasePrimePtr = here->BJTbaseBasePrimeStructPtr->CSC ;
if ((here->BJTemitNode != 0) && (here->BJTemitPrimeNode != 0))
here->BJTemitEmitPrimePtr = here->BJTemitEmitPrimeStructPtr->CSC ;
if ((here->BJTcolPrimeNode != 0) && (here->BJTcolNode != 0))
here->BJTcolPrimeColPtr = here->BJTcolPrimeColStructPtr->CSC ;
if ((here->BJTcolPrimeNode != 0) && (here->BJTbasePrimeNode != 0))
here->BJTcolPrimeBasePrimePtr = here->BJTcolPrimeBasePrimeStructPtr->CSC ;
if ((here->BJTcolPrimeNode != 0) && (here->BJTemitPrimeNode != 0))
here->BJTcolPrimeEmitPrimePtr = here->BJTcolPrimeEmitPrimeStructPtr->CSC ;
if ((here->BJTbasePrimeNode != 0) && (here->BJTbaseNode != 0))
here->BJTbasePrimeBasePtr = here->BJTbasePrimeBaseStructPtr->CSC ;
if ((here->BJTbasePrimeNode != 0) && (here->BJTcolPrimeNode != 0))
here->BJTbasePrimeColPrimePtr = here->BJTbasePrimeColPrimeStructPtr->CSC ;
if ((here->BJTbasePrimeNode != 0) && (here->BJTemitPrimeNode != 0))
here->BJTbasePrimeEmitPrimePtr = here->BJTbasePrimeEmitPrimeStructPtr->CSC ;
if ((here->BJTemitPrimeNode != 0) && (here->BJTemitNode != 0))
here->BJTemitPrimeEmitPtr = here->BJTemitPrimeEmitStructPtr->CSC ;
if ((here->BJTemitPrimeNode != 0) && (here->BJTcolPrimeNode != 0))
here->BJTemitPrimeColPrimePtr = here->BJTemitPrimeColPrimeStructPtr->CSC ;
if ((here->BJTemitPrimeNode != 0) && (here->BJTbasePrimeNode != 0))
here->BJTemitPrimeBasePrimePtr = here->BJTemitPrimeBasePrimeStructPtr->CSC ;
if ((here->BJTcolNode != 0) && (here->BJTcolNode != 0))
here->BJTcolColPtr = here->BJTcolColStructPtr->CSC ;
if ((here->BJTbaseNode != 0) && (here->BJTbaseNode != 0))
here->BJTbaseBasePtr = here->BJTbaseBaseStructPtr->CSC ;
if ((here->BJTemitNode != 0) && (here->BJTemitNode != 0))
here->BJTemitEmitPtr = here->BJTemitEmitStructPtr->CSC ;
if ((here->BJTcolPrimeNode != 0) && (here->BJTcolPrimeNode != 0))
here->BJTcolPrimeColPrimePtr = here->BJTcolPrimeColPrimeStructPtr->CSC ;
if ((here->BJTbasePrimeNode != 0) && (here->BJTbasePrimeNode != 0))
here->BJTbasePrimeBasePrimePtr = here->BJTbasePrimeBasePrimeStructPtr->CSC ;
if ((here->BJTemitPrimeNode != 0) && (here->BJTemitPrimeNode != 0))
here->BJTemitPrimeEmitPrimePtr = here->BJTemitPrimeEmitPrimeStructPtr->CSC ;
if ((here->BJTsubstNode != 0) && (here->BJTsubstNode != 0))
here->BJTsubstSubstPtr = here->BJTsubstSubstStructPtr->CSC ;
if ((here->BJTsubstConNode != 0) && (here->BJTsubstNode != 0))
here->BJTsubstConSubstPtr = here->BJTsubstConSubstStructPtr->CSC ;
if ((here->BJTsubstNode != 0) && (here->BJTsubstConNode != 0))
here->BJTsubstSubstConPtr = here->BJTsubstSubstConStructPtr->CSC ;
if ((here->BJTbaseNode != 0) && (here->BJTcolPrimeNode != 0))
here->BJTbaseColPrimePtr = here->BJTbaseColPrimeStructPtr->CSC ;
if ((here->BJTcolPrimeNode != 0) && (here->BJTbaseNode != 0))
here->BJTcolPrimeBasePtr = here->BJTcolPrimeBaseStructPtr->CSC ;
}
}
return (OK) ;
}

View File

@ -283,6 +283,33 @@ typedef struct sBJTinstance {
#endif /*NONOISE*/
/* the above to avoid allocating memory when it is not needed */
#ifdef KLU
BindElement *BJTcolColPrimeStructPtr ;
BindElement *BJTbaseBasePrimeStructPtr ;
BindElement *BJTemitEmitPrimeStructPtr ;
BindElement *BJTcolPrimeColStructPtr ;
BindElement *BJTcolPrimeBasePrimeStructPtr ;
BindElement *BJTcolPrimeEmitPrimeStructPtr ;
BindElement *BJTbasePrimeBaseStructPtr ;
BindElement *BJTbasePrimeColPrimeStructPtr ;
BindElement *BJTbasePrimeEmitPrimeStructPtr ;
BindElement *BJTemitPrimeEmitStructPtr ;
BindElement *BJTemitPrimeColPrimeStructPtr ;
BindElement *BJTemitPrimeBasePrimeStructPtr ;
BindElement *BJTcolColStructPtr ;
BindElement *BJTbaseBaseStructPtr ;
BindElement *BJTemitEmitStructPtr ;
BindElement *BJTcolPrimeColPrimeStructPtr ;
BindElement *BJTbasePrimeBasePrimeStructPtr ;
BindElement *BJTemitPrimeEmitPrimeStructPtr ;
BindElement *BJTsubstSubstStructPtr ;
BindElement *BJTsubstConSubstStructPtr ;
BindElement *BJTsubstSubstConStructPtr ;
BindElement *BJTsubstConSubstConStructPtr ;
BindElement *BJTbaseColPrimeStructPtr ;
BindElement *BJTcolPrimeBaseStructPtr ;
#endif
} BJTinstance ;
/* entries in the state vector for bjt: */

View File

@ -34,3 +34,9 @@ extern int BJTdSetup(GENmodel*, register CKTcircuit*);
extern int BJTsoaCheck(CKTcircuit *, GENmodel *);
#endif
#ifdef KLU
extern int BJTbindCSC (GENmodel*, CKTcircuit*) ;
extern int BJTbindCSCComplex (GENmodel*, CKTcircuit*) ;
extern int BJTbindCSCComplexToReal (GENmodel*, CKTcircuit*) ;
#endif

View File

@ -73,7 +73,13 @@ SPICEdev BJTinfo = { /* description from struct IFdevice */
/* DEVacct */ NULL,
#endif
/* DEVinstSize */ &BJTiSize,
/* DEVmodSize */ &BJTmSize
/* DEVmodSize */ &BJTmSize,
#ifdef KLU
/* DEVbindCSC */ BJTbindCSC,
/* DEVbindCSCComplex */ BJTbindCSCComplex,
/* DEVbindCSCComplexToReal */ BJTbindCSCComplexToReal,
#endif
};

View File

@ -31,7 +31,11 @@ libbsim1_la_SOURCES = \
bsim1itf.h
if KLU_WANTED
libbsim1_la_SOURCES += b1bindCSC.c
endif
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include
AM_CFLAGS = $(STATIC)
MAINTAINERCLEANFILES = Makefile.in

View File

@ -0,0 +1,393 @@
/**********
Author: 2013 Francesco Lannutti
**********/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "bsim1def.h"
#include "ngspice/sperror.h"
#include <stdlib.h>
static
int
BindCompare (const void *a, const void *b)
{
BindElement *A, *B ;
A = (BindElement *)a ;
B = (BindElement *)b ;
return ((int)(A->Sparse - B->Sparse)) ;
}
int
B1bindCSC (GENmodel *inModel, CKTcircuit *ckt)
{
B1model *model = (B1model *)inModel ;
B1instance *here ;
double *i ;
BindElement *matched, *BindStruct ;
size_t nz ;
BindStruct = ckt->CKTmatrix->CKTbindStruct ;
nz = (size_t)ckt->CKTmatrix->CKTklunz ;
/* loop through all the B1 models */
for ( ; model != NULL ; model = model->B1nextModel)
{
/* loop through all the instances of the model */
for (here = model->B1instances ; here != NULL ; here = here->B1nextInstance)
{
if ((here-> B1dNode != 0) && (here-> B1dNode != 0))
{
i = here->B1DdPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1DdStructPtr = matched ;
here->B1DdPtr = matched->CSC ;
}
if ((here-> B1gNode != 0) && (here-> B1gNode != 0))
{
i = here->B1GgPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1GgStructPtr = matched ;
here->B1GgPtr = matched->CSC ;
}
if ((here-> B1sNode != 0) && (here-> B1sNode != 0))
{
i = here->B1SsPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1SsStructPtr = matched ;
here->B1SsPtr = matched->CSC ;
}
if ((here-> B1bNode != 0) && (here-> B1bNode != 0))
{
i = here->B1BbPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1BbStructPtr = matched ;
here->B1BbPtr = matched->CSC ;
}
if ((here-> B1dNodePrime != 0) && (here-> B1dNodePrime != 0))
{
i = here->B1DPdpPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1DPdpStructPtr = matched ;
here->B1DPdpPtr = matched->CSC ;
}
if ((here-> B1sNodePrime != 0) && (here-> B1sNodePrime != 0))
{
i = here->B1SPspPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1SPspStructPtr = matched ;
here->B1SPspPtr = matched->CSC ;
}
if ((here-> B1dNode != 0) && (here-> B1dNodePrime != 0))
{
i = here->B1DdpPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1DdpStructPtr = matched ;
here->B1DdpPtr = matched->CSC ;
}
if ((here-> B1gNode != 0) && (here-> B1bNode != 0))
{
i = here->B1GbPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1GbStructPtr = matched ;
here->B1GbPtr = matched->CSC ;
}
if ((here-> B1gNode != 0) && (here-> B1dNodePrime != 0))
{
i = here->B1GdpPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1GdpStructPtr = matched ;
here->B1GdpPtr = matched->CSC ;
}
if ((here-> B1gNode != 0) && (here-> B1sNodePrime != 0))
{
i = here->B1GspPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1GspStructPtr = matched ;
here->B1GspPtr = matched->CSC ;
}
if ((here-> B1sNode != 0) && (here-> B1sNodePrime != 0))
{
i = here->B1SspPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1SspStructPtr = matched ;
here->B1SspPtr = matched->CSC ;
}
if ((here-> B1bNode != 0) && (here-> B1dNodePrime != 0))
{
i = here->B1BdpPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1BdpStructPtr = matched ;
here->B1BdpPtr = matched->CSC ;
}
if ((here-> B1bNode != 0) && (here-> B1sNodePrime != 0))
{
i = here->B1BspPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1BspStructPtr = matched ;
here->B1BspPtr = matched->CSC ;
}
if ((here-> B1dNodePrime != 0) && (here-> B1sNodePrime != 0))
{
i = here->B1DPspPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1DPspStructPtr = matched ;
here->B1DPspPtr = matched->CSC ;
}
if ((here-> B1dNodePrime != 0) && (here-> B1dNode != 0))
{
i = here->B1DPdPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1DPdStructPtr = matched ;
here->B1DPdPtr = matched->CSC ;
}
if ((here-> B1bNode != 0) && (here-> B1gNode != 0))
{
i = here->B1BgPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1BgStructPtr = matched ;
here->B1BgPtr = matched->CSC ;
}
if ((here-> B1dNodePrime != 0) && (here-> B1gNode != 0))
{
i = here->B1DPgPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1DPgStructPtr = matched ;
here->B1DPgPtr = matched->CSC ;
}
if ((here-> B1sNodePrime != 0) && (here-> B1gNode != 0))
{
i = here->B1SPgPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1SPgStructPtr = matched ;
here->B1SPgPtr = matched->CSC ;
}
if ((here-> B1sNodePrime != 0) && (here-> B1sNode != 0))
{
i = here->B1SPsPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1SPsStructPtr = matched ;
here->B1SPsPtr = matched->CSC ;
}
if ((here-> B1dNodePrime != 0) && (here-> B1bNode != 0))
{
i = here->B1DPbPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1DPbStructPtr = matched ;
here->B1DPbPtr = matched->CSC ;
}
if ((here-> B1sNodePrime != 0) && (here-> B1bNode != 0))
{
i = here->B1SPbPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1SPbStructPtr = matched ;
here->B1SPbPtr = matched->CSC ;
}
if ((here-> B1sNodePrime != 0) && (here-> B1dNodePrime != 0))
{
i = here->B1SPdpPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B1SPdpStructPtr = matched ;
here->B1SPdpPtr = matched->CSC ;
}
}
}
return (OK) ;
}
int
B1bindCSCComplex (GENmodel *inModel, CKTcircuit *ckt)
{
B1model *model = (B1model *)inModel ;
B1instance *here ;
NG_IGNORE (ckt) ;
/* loop through all the B1 models */
for ( ; model != NULL ; model = model->B1nextModel)
{
/* loop through all the instances of the model */
for (here = model->B1instances ; here != NULL ; here = here->B1nextInstance)
{
if ((here-> B1dNode != 0) && (here-> B1dNode != 0))
here->B1DdPtr = here->B1DdStructPtr->CSC_Complex ;
if ((here-> B1gNode != 0) && (here-> B1gNode != 0))
here->B1GgPtr = here->B1GgStructPtr->CSC_Complex ;
if ((here-> B1sNode != 0) && (here-> B1sNode != 0))
here->B1SsPtr = here->B1SsStructPtr->CSC_Complex ;
if ((here-> B1bNode != 0) && (here-> B1bNode != 0))
here->B1BbPtr = here->B1BbStructPtr->CSC_Complex ;
if ((here-> B1dNodePrime != 0) && (here-> B1dNodePrime != 0))
here->B1DPdpPtr = here->B1DPdpStructPtr->CSC_Complex ;
if ((here-> B1sNodePrime != 0) && (here-> B1sNodePrime != 0))
here->B1SPspPtr = here->B1SPspStructPtr->CSC_Complex ;
if ((here-> B1dNode != 0) && (here-> B1dNodePrime != 0))
here->B1DdpPtr = here->B1DdpStructPtr->CSC_Complex ;
if ((here-> B1gNode != 0) && (here-> B1bNode != 0))
here->B1GbPtr = here->B1GbStructPtr->CSC_Complex ;
if ((here-> B1gNode != 0) && (here-> B1dNodePrime != 0))
here->B1GdpPtr = here->B1GdpStructPtr->CSC_Complex ;
if ((here-> B1gNode != 0) && (here-> B1sNodePrime != 0))
here->B1GspPtr = here->B1GspStructPtr->CSC_Complex ;
if ((here-> B1sNode != 0) && (here-> B1sNodePrime != 0))
here->B1SspPtr = here->B1SspStructPtr->CSC_Complex ;
if ((here-> B1bNode != 0) && (here-> B1dNodePrime != 0))
here->B1BdpPtr = here->B1BdpStructPtr->CSC_Complex ;
if ((here-> B1bNode != 0) && (here-> B1sNodePrime != 0))
here->B1BspPtr = here->B1BspStructPtr->CSC_Complex ;
if ((here-> B1dNodePrime != 0) && (here-> B1sNodePrime != 0))
here->B1DPspPtr = here->B1DPspStructPtr->CSC_Complex ;
if ((here-> B1dNodePrime != 0) && (here-> B1dNode != 0))
here->B1DPdPtr = here->B1DPdStructPtr->CSC_Complex ;
if ((here-> B1bNode != 0) && (here-> B1gNode != 0))
here->B1BgPtr = here->B1BgStructPtr->CSC_Complex ;
if ((here-> B1dNodePrime != 0) && (here-> B1gNode != 0))
here->B1DPgPtr = here->B1DPgStructPtr->CSC_Complex ;
if ((here-> B1sNodePrime != 0) && (here-> B1gNode != 0))
here->B1SPgPtr = here->B1SPgStructPtr->CSC_Complex ;
if ((here-> B1sNodePrime != 0) && (here-> B1sNode != 0))
here->B1SPsPtr = here->B1SPsStructPtr->CSC_Complex ;
if ((here-> B1dNodePrime != 0) && (here-> B1bNode != 0))
here->B1DPbPtr = here->B1DPbStructPtr->CSC_Complex ;
if ((here-> B1sNodePrime != 0) && (here-> B1bNode != 0))
here->B1SPbPtr = here->B1SPbStructPtr->CSC_Complex ;
if ((here-> B1sNodePrime != 0) && (here-> B1dNodePrime != 0))
here->B1SPdpPtr = here->B1SPdpStructPtr->CSC_Complex ;
}
}
return (OK) ;
}
int
B1bindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt)
{
B1model *model = (B1model *)inModel ;
B1instance *here ;
NG_IGNORE (ckt) ;
/* loop through all the B1 models */
for ( ; model != NULL ; model = model->B1nextModel)
{
/* loop through all the instances of the model */
for (here = model->B1instances ; here != NULL ; here = here->B1nextInstance)
{
if ((here-> B1dNode != 0) && (here-> B1dNode != 0))
here->B1DdPtr = here->B1DdStructPtr->CSC ;
if ((here-> B1gNode != 0) && (here-> B1gNode != 0))
here->B1GgPtr = here->B1GgStructPtr->CSC ;
if ((here-> B1sNode != 0) && (here-> B1sNode != 0))
here->B1SsPtr = here->B1SsStructPtr->CSC ;
if ((here-> B1bNode != 0) && (here-> B1bNode != 0))
here->B1BbPtr = here->B1BbStructPtr->CSC ;
if ((here-> B1dNodePrime != 0) && (here-> B1dNodePrime != 0))
here->B1DPdpPtr = here->B1DPdpStructPtr->CSC ;
if ((here-> B1sNodePrime != 0) && (here-> B1sNodePrime != 0))
here->B1SPspPtr = here->B1SPspStructPtr->CSC ;
if ((here-> B1dNode != 0) && (here-> B1dNodePrime != 0))
here->B1DdpPtr = here->B1DdpStructPtr->CSC ;
if ((here-> B1gNode != 0) && (here-> B1bNode != 0))
here->B1GbPtr = here->B1GbStructPtr->CSC ;
if ((here-> B1gNode != 0) && (here-> B1dNodePrime != 0))
here->B1GdpPtr = here->B1GdpStructPtr->CSC ;
if ((here-> B1gNode != 0) && (here-> B1sNodePrime != 0))
here->B1GspPtr = here->B1GspStructPtr->CSC ;
if ((here-> B1sNode != 0) && (here-> B1sNodePrime != 0))
here->B1SspPtr = here->B1SspStructPtr->CSC ;
if ((here-> B1bNode != 0) && (here-> B1dNodePrime != 0))
here->B1BdpPtr = here->B1BdpStructPtr->CSC ;
if ((here-> B1bNode != 0) && (here-> B1sNodePrime != 0))
here->B1BspPtr = here->B1BspStructPtr->CSC ;
if ((here-> B1dNodePrime != 0) && (here-> B1sNodePrime != 0))
here->B1DPspPtr = here->B1DPspStructPtr->CSC ;
if ((here-> B1dNodePrime != 0) && (here-> B1dNode != 0))
here->B1DPdPtr = here->B1DPdStructPtr->CSC ;
if ((here-> B1bNode != 0) && (here-> B1gNode != 0))
here->B1BgPtr = here->B1BgStructPtr->CSC ;
if ((here-> B1dNodePrime != 0) && (here-> B1gNode != 0))
here->B1DPgPtr = here->B1DPgStructPtr->CSC ;
if ((here-> B1sNodePrime != 0) && (here-> B1gNode != 0))
here->B1SPgPtr = here->B1SPgStructPtr->CSC ;
if ((here-> B1sNodePrime != 0) && (here-> B1sNode != 0))
here->B1SPsPtr = here->B1SPsStructPtr->CSC ;
if ((here-> B1dNodePrime != 0) && (here-> B1bNode != 0))
here->B1DPbPtr = here->B1DPbStructPtr->CSC ;
if ((here-> B1sNodePrime != 0) && (here-> B1bNode != 0))
here->B1SPbPtr = here->B1SPbStructPtr->CSC ;
if ((here-> B1sNodePrime != 0) && (here-> B1dNodePrime != 0))
here->B1SPdpPtr = here->B1SPdpStructPtr->CSC ;
}
}
return (OK) ;
}

View File

@ -166,6 +166,30 @@ typedef struct sBSIM1instance {
double **B1nVar;
#endif /* NONOISE */
#ifdef KLU
BindElement *B1DdStructPtr ;
BindElement *B1GgStructPtr ;
BindElement *B1SsStructPtr ;
BindElement *B1BbStructPtr ;
BindElement *B1DPdpStructPtr ;
BindElement *B1SPspStructPtr ;
BindElement *B1DdpStructPtr ;
BindElement *B1GbStructPtr ;
BindElement *B1GdpStructPtr ;
BindElement *B1GspStructPtr ;
BindElement *B1SspStructPtr ;
BindElement *B1BdpStructPtr ;
BindElement *B1BspStructPtr ;
BindElement *B1DPspStructPtr ;
BindElement *B1DPdStructPtr ;
BindElement *B1BgStructPtr ;
BindElement *B1DPgStructPtr ;
BindElement *B1SPgStructPtr ;
BindElement *B1SPsStructPtr ;
BindElement *B1DPbStructPtr ;
BindElement *B1SPbStructPtr ;
BindElement *B1SPdpStructPtr ;
#endif
} B1instance ;

View File

@ -29,3 +29,9 @@ extern int B1temp(GENmodel*,CKTcircuit*);
extern int B1trunc(GENmodel*,CKTcircuit*,double*);
extern int B1disto(int,GENmodel*,CKTcircuit*);
extern int B1dSetup(GENmodel*, register CKTcircuit*);
#ifdef KLU
extern int B1bindCSC (GENmodel*, CKTcircuit*) ;
extern int B1bindCSCComplex (GENmodel*, CKTcircuit*) ;
extern int B1bindCSCComplexToReal (GENmodel*, CKTcircuit*) ;
#endif

View File

@ -73,7 +73,13 @@ SPICEdev B1info = {
/* DEVacct */ NULL,
#endif
/* DEVinstSize */ &B1iSize,
/* DEVmodSize */ &B1mSize
/* DEVmodSize */ &B1mSize,
#ifdef KLU
/* DEVbindCSC */ B1bindCSC,
/* DEVbindCSCComplex */ B1bindCSCComplex,
/* DEVbindCSCComplexToReal */ B1bindCSCComplexToReal,
#endif
};

View File

@ -29,6 +29,9 @@ libbsim2_la_SOURCES = \
bsim2itf.h
if KLU_WANTED
libbsim2_la_SOURCES += b2bindCSC.c
endif
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include
AM_CFLAGS = $(STATIC)

View File

@ -0,0 +1,393 @@
/**********
Author: 2013 Francesco Lannutti
**********/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "bsim2def.h"
#include "ngspice/sperror.h"
#include <stdlib.h>
static
int
BindCompare (const void *a, const void *b)
{
BindElement *A, *B ;
A = (BindElement *)a ;
B = (BindElement *)b ;
return ((int)(A->Sparse - B->Sparse)) ;
}
int
B2bindCSC (GENmodel *inModel, CKTcircuit *ckt)
{
B2model *model = (B2model *)inModel ;
B2instance *here ;
double *i ;
BindElement *matched, *BindStruct ;
size_t nz ;
BindStruct = ckt->CKTmatrix->CKTbindStruct ;
nz = (size_t)ckt->CKTmatrix->CKTklunz ;
/* loop through all the B2 models */
for ( ; model != NULL ; model = model->B2nextModel)
{
/* loop through all the instances of the model */
for (here = model->B2instances ; here != NULL ; here = here->B2nextInstance)
{
if ((here-> B2dNode != 0) && (here-> B2dNode != 0))
{
i = here->B2DdPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2DdStructPtr = matched ;
here->B2DdPtr = matched->CSC ;
}
if ((here-> B2gNode != 0) && (here-> B2gNode != 0))
{
i = here->B2GgPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2GgStructPtr = matched ;
here->B2GgPtr = matched->CSC ;
}
if ((here-> B2sNode != 0) && (here-> B2sNode != 0))
{
i = here->B2SsPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2SsStructPtr = matched ;
here->B2SsPtr = matched->CSC ;
}
if ((here-> B2bNode != 0) && (here-> B2bNode != 0))
{
i = here->B2BbPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2BbStructPtr = matched ;
here->B2BbPtr = matched->CSC ;
}
if ((here-> B2dNodePrime != 0) && (here-> B2dNodePrime != 0))
{
i = here->B2DPdpPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2DPdpStructPtr = matched ;
here->B2DPdpPtr = matched->CSC ;
}
if ((here-> B2sNodePrime != 0) && (here-> B2sNodePrime != 0))
{
i = here->B2SPspPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2SPspStructPtr = matched ;
here->B2SPspPtr = matched->CSC ;
}
if ((here-> B2dNode != 0) && (here-> B2dNodePrime != 0))
{
i = here->B2DdpPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2DdpStructPtr = matched ;
here->B2DdpPtr = matched->CSC ;
}
if ((here-> B2gNode != 0) && (here-> B2bNode != 0))
{
i = here->B2GbPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2GbStructPtr = matched ;
here->B2GbPtr = matched->CSC ;
}
if ((here-> B2gNode != 0) && (here-> B2dNodePrime != 0))
{
i = here->B2GdpPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2GdpStructPtr = matched ;
here->B2GdpPtr = matched->CSC ;
}
if ((here-> B2gNode != 0) && (here-> B2sNodePrime != 0))
{
i = here->B2GspPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2GspStructPtr = matched ;
here->B2GspPtr = matched->CSC ;
}
if ((here-> B2sNode != 0) && (here-> B2sNodePrime != 0))
{
i = here->B2SspPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2SspStructPtr = matched ;
here->B2SspPtr = matched->CSC ;
}
if ((here-> B2bNode != 0) && (here-> B2dNodePrime != 0))
{
i = here->B2BdpPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2BdpStructPtr = matched ;
here->B2BdpPtr = matched->CSC ;
}
if ((here-> B2bNode != 0) && (here-> B2sNodePrime != 0))
{
i = here->B2BspPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2BspStructPtr = matched ;
here->B2BspPtr = matched->CSC ;
}
if ((here-> B2dNodePrime != 0) && (here-> B2sNodePrime != 0))
{
i = here->B2DPspPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2DPspStructPtr = matched ;
here->B2DPspPtr = matched->CSC ;
}
if ((here-> B2dNodePrime != 0) && (here-> B2dNode != 0))
{
i = here->B2DPdPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2DPdStructPtr = matched ;
here->B2DPdPtr = matched->CSC ;
}
if ((here-> B2bNode != 0) && (here-> B2gNode != 0))
{
i = here->B2BgPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2BgStructPtr = matched ;
here->B2BgPtr = matched->CSC ;
}
if ((here-> B2dNodePrime != 0) && (here-> B2gNode != 0))
{
i = here->B2DPgPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2DPgStructPtr = matched ;
here->B2DPgPtr = matched->CSC ;
}
if ((here-> B2sNodePrime != 0) && (here-> B2gNode != 0))
{
i = here->B2SPgPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2SPgStructPtr = matched ;
here->B2SPgPtr = matched->CSC ;
}
if ((here-> B2sNodePrime != 0) && (here-> B2sNode != 0))
{
i = here->B2SPsPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2SPsStructPtr = matched ;
here->B2SPsPtr = matched->CSC ;
}
if ((here-> B2dNodePrime != 0) && (here-> B2bNode != 0))
{
i = here->B2DPbPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2DPbStructPtr = matched ;
here->B2DPbPtr = matched->CSC ;
}
if ((here-> B2sNodePrime != 0) && (here-> B2bNode != 0))
{
i = here->B2SPbPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2SPbStructPtr = matched ;
here->B2SPbPtr = matched->CSC ;
}
if ((here-> B2sNodePrime != 0) && (here-> B2dNodePrime != 0))
{
i = here->B2SPdpPtr ;
matched = (BindElement *) bsearch (&i, BindStruct, nz, sizeof(BindElement), BindCompare) ;
here->B2SPdpStructPtr = matched ;
here->B2SPdpPtr = matched->CSC ;
}
}
}
return (OK) ;
}
int
B2bindCSCComplex (GENmodel *inModel, CKTcircuit *ckt)
{
B2model *model = (B2model *)inModel ;
B2instance *here ;
NG_IGNORE (ckt) ;
/* loop through all the B2 models */
for ( ; model != NULL ; model = model->B2nextModel)
{
/* loop through all the instances of the model */
for (here = model->B2instances ; here != NULL ; here = here->B2nextInstance)
{
if ((here-> B2dNode != 0) && (here-> B2dNode != 0))
here->B2DdPtr = here->B2DdStructPtr->CSC_Complex ;
if ((here-> B2gNode != 0) && (here-> B2gNode != 0))
here->B2GgPtr = here->B2GgStructPtr->CSC_Complex ;
if ((here-> B2sNode != 0) && (here-> B2sNode != 0))
here->B2SsPtr = here->B2SsStructPtr->CSC_Complex ;
if ((here-> B2bNode != 0) && (here-> B2bNode != 0))
here->B2BbPtr = here->B2BbStructPtr->CSC_Complex ;
if ((here-> B2dNodePrime != 0) && (here-> B2dNodePrime != 0))
here->B2DPdpPtr = here->B2DPdpStructPtr->CSC_Complex ;
if ((here-> B2sNodePrime != 0) && (here-> B2sNodePrime != 0))
here->B2SPspPtr = here->B2SPspStructPtr->CSC_Complex ;
if ((here-> B2dNode != 0) && (here-> B2dNodePrime != 0))
here->B2DdpPtr = here->B2DdpStructPtr->CSC_Complex ;
if ((here-> B2gNode != 0) && (here-> B2bNode != 0))
here->B2GbPtr = here->B2GbStructPtr->CSC_Complex ;
if ((here-> B2gNode != 0) && (here-> B2dNodePrime != 0))
here->B2GdpPtr = here->B2GdpStructPtr->CSC_Complex ;
if ((here-> B2gNode != 0) && (here-> B2sNodePrime != 0))
here->B2GspPtr = here->B2GspStructPtr->CSC_Complex ;
if ((here-> B2sNode != 0) && (here-> B2sNodePrime != 0))
here->B2SspPtr = here->B2SspStructPtr->CSC_Complex ;
if ((here-> B2bNode != 0) && (here-> B2dNodePrime != 0))
here->B2BdpPtr = here->B2BdpStructPtr->CSC_Complex ;
if ((here-> B2bNode != 0) && (here-> B2sNodePrime != 0))
here->B2BspPtr = here->B2BspStructPtr->CSC_Complex ;
if ((here-> B2dNodePrime != 0) && (here-> B2sNodePrime != 0))
here->B2DPspPtr = here->B2DPspStructPtr->CSC_Complex ;
if ((here-> B2dNodePrime != 0) && (here-> B2dNode != 0))
here->B2DPdPtr = here->B2DPdStructPtr->CSC_Complex ;
if ((here-> B2bNode != 0) && (here-> B2gNode != 0))
here->B2BgPtr = here->B2BgStructPtr->CSC_Complex ;
if ((here-> B2dNodePrime != 0) && (here-> B2gNode != 0))
here->B2DPgPtr = here->B2DPgStructPtr->CSC_Complex ;
if ((here-> B2sNodePrime != 0) && (here-> B2gNode != 0))
here->B2SPgPtr = here->B2SPgStructPtr->CSC_Complex ;
if ((here-> B2sNodePrime != 0) && (here-> B2sNode != 0))
here->B2SPsPtr = here->B2SPsStructPtr->CSC_Complex ;
if ((here-> B2dNodePrime != 0) && (here-> B2bNode != 0))
here->B2DPbPtr = here->B2DPbStructPtr->CSC_Complex ;
if ((here-> B2sNodePrime != 0) && (here-> B2bNode != 0))
here->B2SPbPtr = here->B2SPbStructPtr->CSC_Complex ;
if ((here-> B2sNodePrime != 0) && (here-> B2dNodePrime != 0))
here->B2SPdpPtr = here->B2SPdpStructPtr->CSC_Complex ;
}
}
return (OK) ;
}
int
B2bindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt)
{
B2model *model = (B2model *)inModel ;
B2instance *here ;
NG_IGNORE (ckt) ;
/* loop through all the B2 models */
for ( ; model != NULL ; model = model->B2nextModel)
{
/* loop through all the instances of the model */
for (here = model->B2instances ; here != NULL ; here = here->B2nextInstance)
{
if ((here-> B2dNode != 0) && (here-> B2dNode != 0))
here->B2DdPtr = here->B2DdStructPtr->CSC ;
if ((here-> B2gNode != 0) && (here-> B2gNode != 0))
here->B2GgPtr = here->B2GgStructPtr->CSC ;
if ((here-> B2sNode != 0) && (here-> B2sNode != 0))
here->B2SsPtr = here->B2SsStructPtr->CSC ;
if ((here-> B2bNode != 0) && (here-> B2bNode != 0))
here->B2BbPtr = here->B2BbStructPtr->CSC ;
if ((here-> B2dNodePrime != 0) && (here-> B2dNodePrime != 0))
here->B2DPdpPtr = here->B2DPdpStructPtr->CSC ;
if ((here-> B2sNodePrime != 0) && (here-> B2sNodePrime != 0))
here->B2SPspPtr = here->B2SPspStructPtr->CSC ;
if ((here-> B2dNode != 0) && (here-> B2dNodePrime != 0))
here->B2DdpPtr = here->B2DdpStructPtr->CSC ;
if ((here-> B2gNode != 0) && (here-> B2bNode != 0))
here->B2GbPtr = here->B2GbStructPtr->CSC ;
if ((here-> B2gNode != 0) && (here-> B2dNodePrime != 0))
here->B2GdpPtr = here->B2GdpStructPtr->CSC ;
if ((here-> B2gNode != 0) && (here-> B2sNodePrime != 0))
here->B2GspPtr = here->B2GspStructPtr->CSC ;
if ((here-> B2sNode != 0) && (here-> B2sNodePrime != 0))
here->B2SspPtr = here->B2SspStructPtr->CSC ;
if ((here-> B2bNode != 0) && (here-> B2dNodePrime != 0))
here->B2BdpPtr = here->B2BdpStructPtr->CSC ;
if ((here-> B2bNode != 0) && (here-> B2sNodePrime != 0))
here->B2BspPtr = here->B2BspStructPtr->CSC ;
if ((here-> B2dNodePrime != 0) && (here-> B2sNodePrime != 0))
here->B2DPspPtr = here->B2DPspStructPtr->CSC ;
if ((here-> B2dNodePrime != 0) && (here-> B2dNode != 0))
here->B2DPdPtr = here->B2DPdStructPtr->CSC ;
if ((here-> B2bNode != 0) && (here-> B2gNode != 0))
here->B2BgPtr = here->B2BgStructPtr->CSC ;
if ((here-> B2dNodePrime != 0) && (here-> B2gNode != 0))
here->B2DPgPtr = here->B2DPgStructPtr->CSC ;
if ((here-> B2sNodePrime != 0) && (here-> B2gNode != 0))
here->B2SPgPtr = here->B2SPgStructPtr->CSC ;
if ((here-> B2sNodePrime != 0) && (here-> B2sNode != 0))
here->B2SPsPtr = here->B2SPsStructPtr->CSC ;
if ((here-> B2dNodePrime != 0) && (here-> B2bNode != 0))
here->B2DPbPtr = here->B2DPbStructPtr->CSC ;
if ((here-> B2sNodePrime != 0) && (here-> B2bNode != 0))
here->B2SPbPtr = here->B2SPbStructPtr->CSC ;
if ((here-> B2sNodePrime != 0) && (here-> B2dNodePrime != 0))
here->B2SPdpPtr = here->B2SPdpStructPtr->CSC ;
}
}
return (OK) ;
}

Some files were not shown because too many files have changed in this diff Show More