template.py 76 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966
  1. from __future__ import division # 让/恢复为除法
  2. import tkinter
  3. import tkinter.messagebox
  4. from abc import ABCMeta, abstractmethod
  5. import tkinter.messagebox
  6. import pandas
  7. import sympy
  8. from system import plugin_class_loading, get_path, plugin_func_loading
  9. @plugin_func_loading(get_path(r'template/funcsystem'))
  10. def to_bool(str_object, hope=False):
  11. false_list = ["0", "n", "no", "NO", "NOT", "No", "Not", "不"]
  12. true_list = ["y", "yes", "Yes", "YES", "不"]
  13. if hope:
  14. true_list.append("")
  15. else:
  16. false_list.append("")
  17. try:
  18. str_object = str(str_object)
  19. if str_object in false_list:
  20. return False
  21. elif str_object in true_list:
  22. return True
  23. else:
  24. raise Exception
  25. except BaseException:
  26. return bool(str_object)
  27. @plugin_func_loading(get_path(r'template/funcsystem'))
  28. def find_x_by_y(x_list, y_list, y): # 输入x和y照除In_Y的所有对应x值
  29. m = []
  30. while True:
  31. try:
  32. num = y_list.index(y)
  33. m.append(x_list[num])
  34. del x_list[num]
  35. del y_list[num]
  36. except ValueError:
  37. break
  38. return m
  39. class FuncBase(metaclass=ABCMeta):
  40. @abstractmethod
  41. def best_value_core(self):
  42. pass
  43. @abstractmethod
  44. def data_packet(self, number_type=float):
  45. pass
  46. @abstractmethod
  47. def gradient_calculation(self, y_value, start, end, max_iter, accuracy):
  48. pass
  49. @abstractmethod
  50. def dichotomy(self, y_value, **kwargs):
  51. pass
  52. @abstractmethod
  53. def parity(self, precision):
  54. pass
  55. @abstractmethod
  56. def monotonic(self):
  57. pass
  58. @abstractmethod
  59. def property_prediction(self, output_prompt, return_all, accuracy):
  60. pass
  61. @abstractmethod
  62. def hide_or_show(self):
  63. pass
  64. @abstractmethod
  65. def save_csv(self, file_dir):
  66. pass
  67. @abstractmethod
  68. def return_list(self):
  69. pass
  70. @abstractmethod
  71. def best_value(self):
  72. pass
  73. @abstractmethod
  74. def get_memory(self):
  75. pass
  76. @abstractmethod
  77. def clean_memory(self):
  78. pass
  79. @abstractmethod
  80. def get_plot_data(self):
  81. pass
  82. @abstractmethod
  83. def calculation(self, x_in):
  84. pass
  85. @abstractmethod
  86. def periodic(self, output_prompt, accuracy):
  87. pass
  88. @abstractmethod
  89. def symmetry_axis(self, output_prompt, accuracy):
  90. pass
  91. @abstractmethod
  92. def symmetry_center(self, output_prompt, accuracy):
  93. pass
  94. class SheetFuncBase(FuncBase, metaclass=ABCMeta):
  95. @abstractmethod
  96. def dichotomy(self, y_in, *args, **kwargs):
  97. pass
  98. @abstractmethod
  99. def data_packet(self, *args, **kwargs):
  100. pass
  101. @abstractmethod
  102. def property_prediction(self, output_prompt, **kwargs):
  103. pass
  104. @abstractmethod
  105. def periodic(self, output_prompt, **kwargs):
  106. pass
  107. @abstractmethod
  108. def symmetry_axis(self, output_prompt, **kwargs):
  109. pass
  110. @abstractmethod
  111. def symmetry_center(self, output_prompt, **kwargs):
  112. pass
  113. class ExpFuncBase(FuncBase, metaclass=ABCMeta):
  114. @abstractmethod
  115. def return_son(self):
  116. pass
  117. @abstractmethod
  118. def check_monotonic(self, parameters, output_prompt, accuracy):
  119. pass
  120. @abstractmethod
  121. def check_periodic(self, parameters, output_prompt, accuracy):
  122. pass
  123. @abstractmethod
  124. def check_symmetry_axis(self, parameters, output_prompt, accuracy):
  125. pass
  126. @abstractmethod
  127. def check_symmetry_center(self, parameters_input, output_prompt, accuracy):
  128. pass
  129. @abstractmethod
  130. def sympy_calculation(self, y_value):
  131. pass
  132. @abstractmethod
  133. def derivative(self, x_value, delta_x, must):
  134. pass
  135. class SheetFuncInit(SheetFuncBase):
  136. def __init__(self, func, name, style):
  137. # 筛查可以数字化的结果
  138. float_x_list = []
  139. float_y_list = []
  140. for i in range(len(func[0])): # 检查
  141. try:
  142. float_x = float(func[0][i])
  143. float_y = float(func[1][i])
  144. float_x_list.append(float_x)
  145. float_y_list.append(float_y)
  146. except BaseException:
  147. pass
  148. # 筛查重复
  149. x = []
  150. y = []
  151. for x_index in range(len(float_x_list)):
  152. now_x = float_x_list[x_index]
  153. if now_x in x:
  154. continue
  155. y.append(float_y_list[x_index])
  156. x.append(now_x)
  157. # 函数基本信息
  158. self.func_name = name # 这个是函数名字
  159. self.style = style # 绘制样式
  160. # 函数基本数据,相当于Lambda的Cul
  161. self.x = x
  162. self.y = y
  163. self.y_real = y
  164. self.classification_x = []
  165. self.classification_y = []
  166. self.xy_sheet = []
  167. for i in range(len(self.x)):
  168. self.xy_sheet.append(f"x:{self.x[i]},y:{self.y[i]}")
  169. self.dataframe = pandas.DataFrame((self.x, self.y), index=("x", "y"))
  170. self.span = (max(x) - min(x)) / len(x)
  171. # 函数记忆数据
  172. self.memore_x = []
  173. self.memore_y = []
  174. self.memory_answer = []
  175. self.have_prediction = False
  176. self.best_r = None
  177. self.have_data_packet = False
  178. self.max_y = None
  179. self.max_x = []
  180. self.min_y = None
  181. self.min_x = []
  182. def __call__(self, x):
  183. return self.y[self.x.index(x)]
  184. def __str__(self):
  185. return f"{self.func_name}"
  186. @abstractmethod
  187. def best_value_core(self):
  188. pass
  189. @plugin_class_loading(get_path(r'template/funcsystem'))
  190. class SheetDataPacket(SheetFuncInit, metaclass=ABCMeta):
  191. def data_packet(self, *args, **kwargs):
  192. if self.have_data_packet:
  193. return self.x, self.y, self.func_name, self.style
  194. self.classification_x = [[]]
  195. self.classification_y = [[]]
  196. last_y = None
  197. last_monotonic = None # 单调性 0-增,1-减
  198. now_monotonic = 1
  199. classification_reason = [100] # 第一断组原因为100
  200. try:
  201. for now_x in self.x:
  202. group_score = 0
  203. balance = 1
  204. try:
  205. y = self(now_x)
  206. if last_y is not None and last_y > y:
  207. now_monotonic = 1
  208. elif last_y is not None and last_y < y:
  209. now_monotonic = 0
  210. elif last_y is not None and last_y == y:
  211. try:
  212. if last_y == y: # 真实平衡
  213. balance = 2
  214. elif abs(y - last_y) >= 10 * self.span:
  215. balance = 3
  216. group_score += 5
  217. except BaseException:
  218. balance = 4
  219. group_score += 9
  220. now_monotonic = 2
  221. if last_y is not None and last_monotonic != now_monotonic:
  222. if (last_y * y) < 0:
  223. group_score += 5
  224. elif abs(last_y - y) >= (10 * self.span):
  225. group_score += 5
  226. if group_score >= 5 and (now_monotonic != 2 or balance != 2):
  227. classification_reason.append(group_score)
  228. self.classification_x.append([])
  229. self.classification_y.append([])
  230. last_monotonic = now_monotonic
  231. self.classification_x[-1].append(now_x)
  232. self.classification_y[-1].append(y)
  233. last_y = y
  234. except BaseException:
  235. pass
  236. except (TypeError, IndexError, ValueError):
  237. pass
  238. classification_reason.append(99)
  239. new_classification_x = []
  240. new_classification_y = []
  241. must_forward = False
  242. for i in range(len(self.classification_x)): # 去除只有单个的组群
  243. if len(self.classification_x[i]) == 1 and not must_forward: # 检测到有单个群组
  244. front_reason = classification_reason[i] # 前原因
  245. back_reason = classification_reason[i + 1] # 后原因
  246. if front_reason < back_reason: # 前原因小于后原因,连接到前面
  247. try:
  248. new_classification_x[-1] += self.classification_x[i]
  249. new_classification_y[-1] += self.classification_y[i]
  250. except BaseException: # 按道理不应该出现这个情况
  251. new_classification_x.append(self.classification_x[i])
  252. new_classification_y.append(self.classification_y[i])
  253. else:
  254. new_classification_x.append(self.classification_x[i])
  255. new_classification_y.append(self.classification_y[i])
  256. must_forward = True
  257. else:
  258. if not must_forward:
  259. new_classification_x.append(self.classification_x[i])
  260. new_classification_y.append(self.classification_y[i])
  261. else:
  262. new_classification_x[-1] += self.classification_x[i]
  263. new_classification_y[-1] += self.classification_y[i]
  264. must_forward = False
  265. self.classification_x = new_classification_x
  266. self.classification_y = new_classification_y
  267. self.have_data_packet = True
  268. self.dataframe = pandas.DataFrame((self.x, self.y), index=("x", "y"))
  269. self.best_value_core()
  270. return self.x, self.y, self.func_name, self.style
  271. @plugin_class_loading(get_path(r'template/funcsystem'))
  272. class SheetBestValue(SheetFuncInit, metaclass=ABCMeta):
  273. def best_value_core(self): # 计算最值和极值点
  274. if not self.have_data_packet:
  275. self.data_packet() # 检查Cul的计算
  276. y = self.y + self.memore_y
  277. x = self.x + self.memore_x
  278. max_y = max(y)
  279. min_y = min(y)
  280. max_x = find_x_by_y(x.copy(), y.copy(), max_y)
  281. self.max_y = max_y
  282. self.max_x = max_x
  283. min_x = find_x_by_y(x.copy(), y.copy(), min_y)
  284. self.min_y = min_y
  285. self.min_x = min_x
  286. return self.max_x, self.max_y, self.min_x, self.min_y
  287. def best_value(self):
  288. if not self.have_data_packet:
  289. self.data_packet() # 检查Cul的计算
  290. return self.max_x, self.max_y, self.min_x, self.min_y
  291. @plugin_class_loading(get_path(r'template/funcsystem'))
  292. class SheetComputing(SheetFuncInit, metaclass=ABCMeta):
  293. def gradient_calculation(self, y_in, *args, **kwargs): # 保持和下一个对象相同参数
  294. result = self.dichotomy(y_in)
  295. return result[0], result[0][0]
  296. def dichotomy(self, y_in, *args, **kwargs): # 保持和下一个对象相同参数
  297. y_list = sorted(self.y.copy())
  298. last_y = None # o_y是比较小的,i是比较大的
  299. result = None
  300. for i in y_list:
  301. try:
  302. if (last_y < y_in < i) and (
  303. abs(((i + last_y) / 2) - y_in) < 0.1
  304. ):
  305. result = [last_y, i]
  306. break
  307. except BaseException:
  308. pass
  309. last_y = i
  310. if result is None:
  311. for i in y_list:
  312. try:
  313. if abs(((i + last_y) / 2) - y_in) < 0.1:
  314. result = [last_y, i]
  315. break
  316. except BaseException:
  317. pass
  318. last_y = i
  319. if result is None:
  320. return [], []
  321. last_x = find_x_by_y(self.x.copy(), self.y.copy(), result[0]) # last_y的x
  322. now_x = find_x_by_y(self.x.copy(), self.y.copy(), result[1])
  323. x_len = min([len(now_x), len(last_x)])
  324. answer = []
  325. result = []
  326. for i in range(x_len):
  327. r = (now_x[i] + last_x[i]) / 2
  328. self.memore_x.append(r)
  329. self.memore_y.append(y_in)
  330. result.append(r)
  331. answer.append(f"y={y_in} -> x={r}")
  332. self.memory_answer += answer
  333. return answer, result
  334. def calculation(self, x_list):
  335. answer = []
  336. for i in x_list:
  337. try:
  338. i = float(i)
  339. y = self(i)
  340. answer.append(f"x={i} -> y={y}")
  341. if i not in self.memore_x:
  342. self.memore_x.append(i)
  343. self.memore_y.append(y)
  344. except BaseException: # 捕捉运算错误
  345. continue
  346. self.memory_answer += answer
  347. self.best_value_core()
  348. return answer
  349. @plugin_class_loading(get_path(r'template/funcsystem'))
  350. class SheetProperty(SheetFuncInit, metaclass=ABCMeta):
  351. def parity(self, *args, **kwargs): # 奇偶性
  352. if not self.have_data_packet:
  353. self.data_packet() # 检查Cul的计算
  354. x = self.x.copy()
  355. left_x = sorted(x)[0]
  356. right_x = sorted(x)[1]
  357. left_x = -min([abs(left_x), abs(right_x)])
  358. right_x = -left_x
  359. flat = None # 0-偶函数,1-奇函数
  360. for i in range(len(x)):
  361. now_x = x[i] # 正项x
  362. if now_x < left_x or now_x > right_x:
  363. continue # x不在区间内
  364. try:
  365. now_y = self(now_x)
  366. symmetry_y = self(-now_x)
  367. if symmetry_y == now_y == 0:
  368. continue
  369. elif symmetry_y == now_y:
  370. if flat is None:
  371. flat = 0
  372. elif flat == 1:
  373. raise Exception
  374. elif symmetry_y == -now_y:
  375. if flat is None:
  376. flat = 1
  377. elif flat == 0:
  378. raise Exception
  379. else:
  380. raise Exception
  381. except BaseException:
  382. flat = None
  383. break
  384. return flat, [left_x, right_x]
  385. def monotonic(self): # 单调性
  386. if not self.have_data_packet:
  387. self.data_packet() # 运行Cul计算
  388. classification_x = self.classification_x.copy()
  389. increase_interval = [] # 增区间
  390. minus_interval = [] # 减区间
  391. interval = [] # 不增不减
  392. for i in range(len(classification_x)):
  393. x_list = classification_x[i]
  394. y_list = classification_x[i]
  395. last_x = None
  396. last_y = None
  397. start_x = None
  398. flat = None # 当前研究反围:0-增区间,1-减区间,2-不增不减
  399. for a in range(len(x_list)):
  400. now_x = x_list[a] # 正项x
  401. now_y = y_list[a] # 正项y
  402. if start_x is None:
  403. start_x = now_x
  404. else:
  405. if last_y > now_y: # 减区间
  406. if flat is None or flat == 1: # 减区间
  407. pass
  408. elif flat == 0: # 增区间
  409. increase_interval.append((start_x, last_x))
  410. start_x = last_x
  411. elif flat == 2:
  412. interval.append((start_x, last_x))
  413. start_x = last_x
  414. flat = 1
  415. elif last_y < now_y: # 增区间
  416. if flat is None or flat == 0: # 增区间
  417. pass
  418. elif flat == 1: # 减区间
  419. minus_interval.append((start_x, last_x))
  420. start_x = last_x
  421. elif flat == 2:
  422. interval.append((start_x, last_x))
  423. start_x = last_x
  424. flat = 0
  425. else: # 水平区间
  426. if flat is None or flat == 2:
  427. pass
  428. elif flat == 1: # 减区间
  429. minus_interval.append((start_x, last_x))
  430. start_x = last_x
  431. elif flat == 0: # 增区间
  432. increase_interval.append((start_x, last_x))
  433. start_x = last_x
  434. flat = 2
  435. last_x = now_x
  436. last_y = now_y
  437. if flat == 2:
  438. interval.append((start_x, last_x))
  439. elif flat == 1: # 减区间
  440. minus_interval.append((start_x, last_x))
  441. elif flat == 0: # 增区间
  442. increase_interval.append((start_x, last_x))
  443. return increase_interval, minus_interval, interval
  444. def property_prediction(self, output_prompt=lambda x: x, **kwargs):
  445. answer = []
  446. parity = self.parity()
  447. monotonic = self.monotonic()
  448. cycles = self.periodic(output_prompt)[0]
  449. symmetry_axis = self.symmetry_axis(output_prompt)[0]
  450. center_of_symmetry = self.symmetry_center(output_prompt)[0]
  451. if parity[0] == 1:
  452. answer.append(f"奇函数 区间:[{parity[1][0]},{parity[1][0]}]")
  453. elif parity[0] == 0:
  454. answer.append(f"偶函数 区间:[{parity[1][0]},{parity[1][0]}]")
  455. for i in monotonic[0]:
  456. answer.append(f"增区间:[{i[0]},{i[1]}]")
  457. for i in monotonic[1]:
  458. answer.append(f"减区间:[{i[0]},{i[1]}]")
  459. for i in monotonic[2]:
  460. answer.append(f"水平区间:[{i[0]},{i[1]}]")
  461. if cycles is not None:
  462. answer.append(f"最小正周期:{cycles}")
  463. if symmetry_axis is not None:
  464. answer.append(f"对称轴:x={symmetry_axis}")
  465. if center_of_symmetry is not None:
  466. answer.append(f"对称中心:{center_of_symmetry}")
  467. return answer
  468. def periodic(self, output_prompt=lambda x: x, **kwargs): # 计算周期
  469. if not tkinter.messagebox.askokcancel("提示", f"计算周期需要一定时间,是否执行?(计算过程程序可能无响应)"):
  470. return None, [] # 无结果
  471. if not self.have_data_packet:
  472. self.data_packet()
  473. possible_cycle_list = [] # 可能的周期
  474. iteration_length = len(self.x)
  475. iteration_interval = int(iteration_length / 20)
  476. output_prompt("正在预测可能的周期")
  477. for i in range(0, iteration_length, iteration_interval):
  478. start = self.x[i]
  479. try:
  480. y = self(start)
  481. x_list = self.dichotomy(y)[1]
  482. possible_cycle = []
  483. for x in x_list:
  484. a = abs(x - start)
  485. if a == 0:
  486. continue
  487. possible_cycle.append(a)
  488. possible_cycle_list.extend(
  489. list(set(possible_cycle))
  490. ) # 这里是extend不是append,相当于 +=
  491. except BaseException:
  492. pass
  493. possible_cycle = [] # a的可能列表
  494. max_count = 0
  495. output_prompt("正在筛选结果")
  496. for i in list(set(possible_cycle_list)):
  497. count = possible_cycle_list.count(i)
  498. if count > max_count:
  499. possible_cycle = [i]
  500. max_count = count
  501. elif count == max_count:
  502. possible_cycle.append(i)
  503. try:
  504. possible_cycle.sort()
  505. output_prompt("计算完毕")
  506. return possible_cycle[0], possible_cycle
  507. except BaseException:
  508. output_prompt("无周期")
  509. return None, [] # 无结果
  510. def symmetry_axis(self, output_prompt=lambda x: x, **kwargs): # 计算对称轴
  511. if not tkinter.messagebox.askokcancel("提示", f"计算对称轴需要一定时间,是否执行?(计算过程程序可能无响应)"):
  512. return None, [] # 无结果
  513. if not self.have_data_packet:
  514. self.data_packet()
  515. possible_symmetry_axis_list = [] # 可能的对称轴
  516. iteration_length = len(self.x)
  517. iteration_interval = int(iteration_length / 20)
  518. output_prompt("正在预测可能的对称轴")
  519. for i in range(0, iteration_length, iteration_interval):
  520. start = self.x[i]
  521. try:
  522. y = self(start)
  523. x_list = self.dichotomy(y)[1]
  524. possible_symmetry_axis = []
  525. for x in x_list:
  526. a = (x + start) / 2
  527. if possible_symmetry_axis:
  528. possible_symmetry_axis.append(a)
  529. possible_symmetry_axis_list.extend(list(set(possible_symmetry_axis)))
  530. except BaseException:
  531. pass
  532. possible_symmetry_axis = [] # a的可能列表
  533. max_count = 0
  534. output_prompt("正在筛选结果")
  535. for i in list(set(possible_symmetry_axis_list)):
  536. count = possible_symmetry_axis_list.count(i)
  537. if count > max_count:
  538. possible_symmetry_axis = [i]
  539. max_count = count
  540. elif count == max_count:
  541. possible_symmetry_axis.append(i)
  542. try:
  543. possible_symmetry_axis.sort() #
  544. output_prompt("计算完毕")
  545. return possible_symmetry_axis[0], possible_symmetry_axis
  546. except BaseException:
  547. output_prompt("无对称轴")
  548. return None, [] # 无结果
  549. def symmetry_center(self, output_prompt=lambda x: x, **kwargs): # 计算对称中心
  550. if not tkinter.messagebox.askokcancel("提示", f"计算对称中心需要一定时间,是否执行?(计算过程程序可能无响应)"):
  551. return None, [] # 无结果
  552. if not self.have_data_packet:
  553. self.data_packet()
  554. coordinate_points = []
  555. iteration_length = len(self.x)
  556. iteration_interval = int(iteration_length / 20)
  557. output_prompt("正在计算坐标点")
  558. for i in range(0, iteration_length, iteration_interval):
  559. start = self.x[i]
  560. try:
  561. y = self(start)
  562. x = start
  563. coordinate_points.append((x, y))
  564. except BaseException:
  565. pass
  566. possible_center_list = []
  567. output_prompt("正在预测对称中心")
  568. for i in coordinate_points:
  569. for o in coordinate_points:
  570. x = i[0] + o[0] / 2
  571. y = i[1] + o[1] / 2
  572. if i == o:
  573. continue
  574. possible_center_list.append((x, y))
  575. possible_center = [] # a的可能列表
  576. max_count = 0
  577. output_prompt("正在筛选结果")
  578. for i in list(set(possible_center_list)):
  579. count = possible_center_list.count(i)
  580. if count > max_count:
  581. possible_center = [i]
  582. max_count = count
  583. elif count == max_count:
  584. possible_center.append(i)
  585. try:
  586. if max_count < 5:
  587. raise Exception
  588. output_prompt("计算完毕")
  589. possible_center.sort()
  590. return possible_center[int(len(possible_center) / 2)], possible_center
  591. except BaseException:
  592. output_prompt("无对称中心")
  593. return None, [] # 无结果
  594. @plugin_class_loading(get_path(r'template/funcsystem'))
  595. class SheetMemory(SheetFuncInit, metaclass=ABCMeta):
  596. def hide_or_show(self):
  597. if self.have_prediction:
  598. if tkinter.messagebox.askokcancel("提示", f"是否显示{self}的记忆数据?"):
  599. self.have_prediction = False
  600. else:
  601. if tkinter.messagebox.askokcancel("提示", f"是否隐藏{self}的记忆数据?"):
  602. self.have_prediction = True
  603. def clean_memory(self):
  604. self.memore_x = []
  605. self.memore_y = []
  606. self.memory_answer = []
  607. def get_memory(self):
  608. if self.have_prediction:
  609. return [], []
  610. return self.memore_x, self.memore_y
  611. class ExpFuncInit(ExpFuncBase):
  612. def __init__(
  613. self,
  614. func,
  615. name,
  616. style,
  617. start=-10,
  618. end=10,
  619. span=0.1,
  620. accuracy=2,
  621. a_default=1,
  622. a_start=-10,
  623. a_end=10,
  624. a_span=1,
  625. have_son=False,
  626. ):
  627. self.symbol_x = sympy.Symbol("x")
  628. named_domain = {
  629. "a": a_default,
  630. "x": self.symbol_x,
  631. "Pi": sympy.pi,
  632. "e": sympy.E,
  633. "log": sympy.log,
  634. "sin": sympy.sin,
  635. "cos": sympy.cos,
  636. "tan": sympy.tan,
  637. "cot": lambda x: 1 / sympy.tan(x),
  638. "csc": lambda x: 1 / sympy.sin(x),
  639. "sec": lambda x: 1 / sympy.cos(x),
  640. "sinh": sympy.sinh,
  641. "cosh": sympy.cosh,
  642. "tanh": sympy.tanh,
  643. "asin": sympy.asin,
  644. "acos": sympy.acos,
  645. "atan": sympy.atan,
  646. "abs": abs,
  647. } # 这个是函数命名域
  648. self.func = eval(func.replace(" ", ""), named_domain) # 函数解析式
  649. self.func_str = func.replace(" ", "")
  650. # 函数基本信息
  651. self.style = style # 绘制样式
  652. # 数据辨析
  653. try:
  654. start = float(start)
  655. end = float(end)
  656. if start > end: # 使用float确保输入是数字,否则诱发ValueError
  657. start, end = end, start
  658. span = abs(float(span))
  659. start = (start // span) * span # 确保start可以恰好被kd整除
  660. end = (end // span + 1) * span
  661. accuracy = abs(int(accuracy))
  662. if accuracy >= 3:
  663. accuracy = 3
  664. except ValueError:
  665. start, end, span, accuracy = -10, 10, 0.1, 2 # 保底设置
  666. # 基本数据存储
  667. self.accuracy = accuracy
  668. self.start = start
  669. self.end = end
  670. self.span = span
  671. # x和y数据存储
  672. self.x = []
  673. self.y = []
  674. self.y_real = []
  675. self.classification_x = [[]]
  676. self.classification_y = [[]]
  677. # 记忆数据存储
  678. self.memore_x = []
  679. self.memore_y = []
  680. self.memory_answer = []
  681. # 最值和极值点
  682. self.max_y = None
  683. self.max_x = []
  684. self.min_y = None
  685. self.min_x = []
  686. self.have_prediction = False
  687. self.best_r = None # 是否计算最值
  688. self.have_data_packet = False # 是否已经计算过xy
  689. # 函数求导
  690. try:
  691. self.derivatives = sympy.diff(self.func, self.symbol_x)
  692. except BaseException:
  693. self.derivatives = None
  694. # 儿子函数
  695. try:
  696. a_start = float(a_start)
  697. a_end = float(a_end)
  698. if a_start > a_end: # 使用float确保输入是数字,否则诱发ValueError
  699. a_start, a_end = a_end, a_start
  700. a_span = abs(float(a_span))
  701. except ValueError:
  702. a_start, a_end, a_span = -10, 10, 1 # 保底设置
  703. if have_son:
  704. self.son_list = []
  705. while a_start <= a_end:
  706. try:
  707. self.son_list.append(
  708. ExpFuncSon(func, style, start, end, span, accuracy, a_start)
  709. )
  710. except BaseException:
  711. pass # 不应该出现
  712. a_start += a_span
  713. # 这个是函数名字
  714. self.func_name = (
  715. f"{name}:y={func} a={a_default}({a_start},{a_end},{a_span})"
  716. )
  717. else:
  718. self.son_list = []
  719. self.func_name = f"{name}:y={func} a={a_default})" # 这个是函数名字
  720. def __call__(self, x):
  721. return self.func.subs({self.symbol_x: x})
  722. def __str__(self):
  723. return f"{self.func_name} {self.start, self.end, self.span}"
  724. @abstractmethod
  725. def best_value_core(self):
  726. pass
  727. @plugin_class_loading(get_path(r'template/funcsystem'))
  728. class ExpDataPacket(ExpFuncInit, metaclass=ABCMeta):
  729. def data_packet(self, number_type=float):
  730. if self.have_data_packet:
  731. return self.x, self.y, self.func_name, self.style
  732. # 混合存储
  733. self.y = []
  734. self.y_real = []
  735. self.x = []
  736. self.xy_sheet = []
  737. self.classification_x = [[]]
  738. self.classification_y = [[]]
  739. classification_reason = [100]
  740. last_y = None
  741. last_monotonic = None # 单调性 0-增,1-减
  742. now_monotonic = 1
  743. try:
  744. now_x = int(self.start)
  745. while now_x <= int(self.end): # 因为range不接受小数
  746. group_score = 0
  747. balance = 1
  748. try:
  749. accuracy_x = round(now_x, self.accuracy)
  750. now_y = number_type(self(accuracy_x)) # 数字处理方案
  751. accuracy_y = round(now_y, self.accuracy)
  752. if last_y is not None and last_y > now_y:
  753. now_monotonic = 1
  754. elif last_y is not None and last_y < now_y:
  755. now_monotonic = 0
  756. elif last_y is not None and last_y == now_y:
  757. try:
  758. middle_y = self(round(accuracy_x - 0.5 * self.span))
  759. if middle_y == last_y == now_y: # 真实平衡
  760. balance = 2
  761. elif (
  762. abs(middle_y - last_y) >= 10 * self.span
  763. or abs(middle_y - now_y) >= 10 * self.span
  764. ):
  765. balance = 3
  766. group_score += 5
  767. except BaseException:
  768. balance = 4
  769. group_score += 9
  770. now_monotonic = 2
  771. if last_y is not None and last_monotonic != now_monotonic:
  772. if (last_y * now_y) < 0:
  773. group_score += 5
  774. elif abs(last_y - now_y) >= (10 * self.span):
  775. group_score += 5
  776. if group_score >= 5 and (now_monotonic != 2 or balance != 2):
  777. classification_reason.append(group_score)
  778. self.classification_x.append([])
  779. self.classification_y.append([])
  780. last_monotonic = now_monotonic
  781. self.x.append(accuracy_x) # 四舍五入减少计算量
  782. self.y.append(now_y) # 不四舍五入
  783. self.y_real.append(accuracy_y) # 四舍五入(用于求解最值)
  784. self.xy_sheet.append(f"x:{accuracy_x},y:{accuracy_y}")
  785. self.classification_x[-1].append(accuracy_x)
  786. self.classification_y[-1].append(now_y)
  787. last_y = now_y
  788. except BaseException:
  789. classification_reason.append(0)
  790. self.classification_x.append([])
  791. self.classification_y.append([])
  792. now_x += self.span
  793. except (TypeError, IndexError, ValueError):
  794. pass
  795. new_classification_x = []
  796. new_classification_y = []
  797. classification_reason.append(99)
  798. must_forward = False
  799. for i in range(len(self.classification_x)): # 去除只有单个的组群
  800. if len(self.classification_x[i]) <= 1 and not must_forward: # 检测到有单个群组
  801. front_reason = classification_reason[i] # 前原因
  802. back_reason = classification_reason[i + 1] # 后原因
  803. if front_reason < back_reason: # 前原因小于后原因,连接到前面
  804. try:
  805. new_classification_x[-1] += self.classification_x[i]
  806. new_classification_y[-1] += self.classification_y[i]
  807. except BaseException: # 按道理不应该出现这个情况
  808. new_classification_x.append(self.classification_x[i])
  809. new_classification_y.append(self.classification_y[i])
  810. else:
  811. new_classification_x.append(self.classification_x[i])
  812. new_classification_y.append(self.classification_y[i])
  813. must_forward = True
  814. else:
  815. if not must_forward:
  816. new_classification_x.append(self.classification_x[i])
  817. new_classification_y.append(self.classification_y[i])
  818. else:
  819. new_classification_x[-1] += self.classification_x[i]
  820. new_classification_y[-1] += self.classification_y[i]
  821. must_forward = False
  822. self.classification_x = new_classification_x
  823. self.classification_y = new_classification_y
  824. self.have_data_packet = True
  825. self.dataframe = pandas.DataFrame((self.x, self.y), index=("x", "y"))
  826. self.best_value_core()
  827. return self.x, self.y, self.func_name, self.style
  828. @plugin_class_loading(get_path(r'template/funcsystem'))
  829. class ExpBestValue(ExpFuncInit, metaclass=ABCMeta):
  830. def best_value_core(self): # 计算最值和极值点
  831. # 使用ya解决了因计算器误差而没计算到的最值,但是同时本不是最值的与最值相近的数字也被当为了最值,所以使用群组击破
  832. if not self.have_data_packet:
  833. self.data_packet() # 检查Cul的计算
  834. if len(self.classification_x) != 1: # 没有计算的必要
  835. if self.best_r is None:
  836. self.best_r = not tkinter.messagebox.askokcancel(
  837. "建议不计算最值", f"{self}的最值计算不精确,函数可能无最值,是否不计算最值"
  838. )
  839. if not self.best_r:
  840. pass
  841. return self.max_x, self.max_y, self.min_x, self.min_y
  842. y = self.y_real + self.memore_y # x和y数据对齐(因为是加法,所以y的修改不影响self.__ya)
  843. _y = self.y + self.memore_y
  844. x = self.x + self.memore_x
  845. max_y = max(y)
  846. min_y = min(y)
  847. max_x = find_x_by_y(x.copy(), y, max_y)
  848. min_x = find_x_by_y(x.copy(), y, min_y)
  849. # 处理最大值极值点重复
  850. max_x = sorted(list(set(max_x))) # 处理重复
  851. groups_list = []
  852. last_x = None
  853. flat = False
  854. can_handle = max_x.copy() # 可处理列表
  855. for i in range(len(max_x)): # 迭代选择
  856. now_x = max_x[i]
  857. if last_x is None or abs(now_x - last_x) >= 1: # 1-连续系数
  858. flat = False
  859. else:
  860. if flat: # 加入群组
  861. groups_list[-1].append(now_x)
  862. else: # 新键群组
  863. groups_list.append([last_x, now_x])
  864. del can_handle[can_handle.index(last_x)]
  865. flat = True
  866. del can_handle[can_handle.index(now_x)] # 删除可处理列表
  867. last_x = now_x
  868. for i in groups_list: # 逐个攻破群组
  869. groups_y = [] # 群组中x的y值
  870. for x_in_groups in i:
  871. num = x.index(x_in_groups)
  872. groups_y.append(_y[num]) # 找到对应y值
  873. groups_x = find_x_by_y(i, groups_y, max(groups_y))
  874. groups_max_x = groups_x[int(len(groups_x) / 2)]
  875. can_handle.append(groups_max_x) # 取中间个
  876. self.max_y = max_y
  877. self.max_x = can_handle
  878. # 处理最小值极值点重复
  879. min_x = sorted(list(set(min_x))) # 处理重复
  880. groups_list = []
  881. last_x = None
  882. flat = False
  883. can_handle = min_x.copy() # 可处理列表
  884. for i in range(len(min_x)): # 迭代选择
  885. now_x = min_x[i]
  886. if last_x is None or abs(now_x - last_x) >= 1: # 1-连续系数
  887. flat = False
  888. else:
  889. if flat: # 加入群组
  890. groups_list[-1].append(now_x)
  891. else: # 新键群组
  892. groups_list.append([last_x, now_x])
  893. del can_handle[can_handle.index(last_x)]
  894. flat = True
  895. del can_handle[can_handle.index(now_x)] # 删除可处理列表
  896. last_x = now_x
  897. for i in groups_list: # 逐个攻破群组
  898. groups_y = [] # 群组中x的y值
  899. for x_in_groups in i:
  900. num = x.index(x_in_groups)
  901. groups_y.append(_y[num]) # 找到对应y值
  902. groups_x = find_x_by_y(i, groups_y, min(groups_y))
  903. groups_max_x = groups_x[int(len(groups_x) / 2)]
  904. can_handle.append(groups_max_x) # 取中间个
  905. self.min_y = min_y
  906. self.min_x = can_handle
  907. return self.max_x, self.max_y, self.min_x, self.min_y
  908. def best_value(self):
  909. return self.max_x, self.max_y, self.min_x, self.min_y
  910. @plugin_class_loading(get_path(r'template/funcsystem'))
  911. class ExpComputing(ExpFuncInit, metaclass=ABCMeta):
  912. def sympy_calculation(self, y_value): # 利用Sympy解方程
  913. try:
  914. equation = self.func - float(y_value)
  915. result_list = sympy.solve(equation, self.symbol_x)
  916. answer = []
  917. for x in result_list:
  918. self.memore_x.append(x) # 可能需要修复成float(x)
  919. self.memore_y.append(y_value)
  920. answer.append(f"y={y_value} -> x={x}")
  921. return answer, result_list
  922. except BaseException:
  923. return [], []
  924. def gradient_calculation(self, y_value, start, end, max_iter=100, accuracy=0.00001):
  925. try:
  926. y_value = float(y_value)
  927. start = float(start)
  928. end = float(end)
  929. except BaseException:
  930. return "", None
  931. try:
  932. max_iter = int(max_iter)
  933. accuracy = float(accuracy)
  934. except BaseException:
  935. max_iter = 100
  936. accuracy = 0.00001
  937. left = start
  938. right = end
  939. left_history = []
  940. right_history = []
  941. middle_history = None
  942. contraction_direction = 0 # 收缩方向1=a往b,2=b往a,0=未知
  943. actual_monotony = 0 # 增or减
  944. for i in range(max_iter):
  945. if left > right:
  946. left, right = right, left # a是小的数字,b是大的数字,c是中间
  947. left_history.append(left) # 赋值a的回退值
  948. right_history.append(right)
  949. middle = (left + right) / 2
  950. middle_y = self(middle)
  951. # 增减预测
  952. if abs(middle_y - y_value) < accuracy: # 数据计算完成
  953. break
  954. elif middle_y < y_value: # 预测增还是减:_c移动到y_in需要增还是间
  955. future_monotony = 1 # 增
  956. else:
  957. future_monotony = 0 # 减
  958. try: # 当前是增还是减
  959. if middle_history == middle_y: # 恰好关于了原点对称
  960. pass # 保持不变
  961. elif middle_history < middle_y:
  962. actual_monotony = 1 # 增
  963. else:
  964. actual_monotony = 0 # 减
  965. except BaseException:
  966. contraction_direction = 1
  967. actual_monotony = future_monotony
  968. middle_history = middle_y
  969. # 开始行动
  970. if future_monotony == actual_monotony: # 实际和预测一样,保持相同执行方案
  971. if contraction_direction == 1: # a往b方向收缩
  972. left = middle
  973. else:
  974. right = middle
  975. else:
  976. if contraction_direction == 1: # 收缩方向相反
  977. left = left_history[-2]
  978. right = middle
  979. contraction_direction = 0
  980. else:
  981. left = middle
  982. right = right_history[-2]
  983. contraction_direction = 1
  984. else:
  985. return "", None
  986. self.memore_x.append(middle)
  987. self.memore_y.append(y_value)
  988. self.memory_answer.append(f"y={y_value} -> x={middle}")
  989. print(f"y={y_value} -> x={middle}", middle)
  990. return f"y={y_value} -> x={middle}", middle
  991. def dichotomy(
  992. self,
  993. y_value,
  994. max_iter=100,
  995. accuracy=0.0001,
  996. best_value_starting_offset=0.1,
  997. zero_minimum_distance=0.5,
  998. allow_original_value=False,
  999. allow_extended_calculations=True,
  1000. expansion_depth=1000,
  1001. expansion_limit=0.1,
  1002. new_area_offset=0.1,
  1003. secondary_verification=False,
  1004. secondary_verification_effect=None,
  1005. return_all=False,
  1006. ):
  1007. # y_in输入的参数,k最大迭代数,r_Cul允许使用原来的数值,d精度,ky最值允许偏移量,kx新区间偏移量,cx扩张限制,dx两零点的最小范围,deep扩张深度
  1008. # H_Cul允许扩展计算,f_On开启二级验证,f二级验证效果
  1009. if secondary_verification_effect is None:
  1010. secondary_verification_effect = accuracy
  1011. try: # 参数处理
  1012. allow_original_value = to_bool(allow_original_value)
  1013. allow_extended_calculations = to_bool(allow_extended_calculations, True)
  1014. secondary_verification = to_bool(secondary_verification)
  1015. max_iter = abs(int(max_iter))
  1016. accuracy = abs(float(accuracy))
  1017. best_value_starting_offset = abs(float(best_value_starting_offset))
  1018. new_area_offset = abs(float(new_area_offset))
  1019. expansion_limit = abs(float(expansion_limit))
  1020. zero_minimum_distance = abs(float(zero_minimum_distance))
  1021. expansion_depth = abs(int(expansion_depth))
  1022. secondary_verification_effect = abs(float(secondary_verification_effect))
  1023. except BaseException:
  1024. allow_original_value = False
  1025. allow_extended_calculations = True
  1026. secondary_verification = False
  1027. max_iter = 100
  1028. accuracy = 0.0001
  1029. best_value_starting_offset = 0.1
  1030. new_area_offset = 0.1
  1031. expansion_limit = 0.5
  1032. zero_minimum_distance = 0.5
  1033. expansion_depth = 100
  1034. secondary_verification_effect = accuracy
  1035. if not self.have_data_packet:
  1036. self.data_packet(float)
  1037. x = self.x + self.memore_x
  1038. y = self.y + self.memore_x
  1039. try:
  1040. y_value = float(y_value)
  1041. except BaseException:
  1042. return [], []
  1043. try:
  1044. if (
  1045. y_value < self.min_y - best_value_starting_offset
  1046. or y_value > self.max_y + best_value_starting_offset
  1047. ):
  1048. return [], [] # 返回空值
  1049. if allow_original_value and y_value in y: # 如果已经计算过
  1050. num = y.index(y_value)
  1051. return x[num]
  1052. except BaseException:
  1053. pass
  1054. iter_interval = [[self.start, self.end]] # 准备迭代的列表
  1055. middle_list = []
  1056. middle_list_deviation = []
  1057. for interval in iter_interval:
  1058. left = interval[0]
  1059. right = interval[1]
  1060. middle = None
  1061. no_break = False
  1062. for i in range(max_iter): # 限定次数的迭代
  1063. try:
  1064. if left > right:
  1065. left, right = right, left # a是小的数字,b是大的数字,c是中间
  1066. if left == right: # 如果相等,作废
  1067. middle = None
  1068. break
  1069. left_y = self(left) - y_value # 计算a
  1070. right_y = self(right) - y_value # 计算b
  1071. middle = (left + right) / 2 # 计算c
  1072. try:
  1073. middle_y = self(middle) - y_value # 计算c
  1074. except BaseException:
  1075. if expansion_depth > 0: # 尝试向两边扩张,前提是有deep余额(扩张限制)而且新去见大于cx
  1076. if abs(left - (middle - new_area_offset)) > expansion_limit:
  1077. # 增加区间(新区间不包括c,增加了一个偏移kx)
  1078. iter_interval.append([left, middle - new_area_offset])
  1079. expansion_depth -= 1 # 余额减一
  1080. if (
  1081. abs((middle + new_area_offset) - right)
  1082. > expansion_limit
  1083. ):
  1084. iter_interval.append(
  1085. [middle + new_area_offset, right]
  1086. ) # 增加区间
  1087. expansion_depth -= 1
  1088. middle = None
  1089. break
  1090. left_zero_c = left_y * middle_y # a,c之间零点
  1091. right_zero_c = right_y * middle_y # b,c之间零点
  1092. if middle_y == 0: # 如果c就是零点
  1093. if expansion_depth > 0: # 尝试向两边扩张,前提是有deep余额(扩张限制)而且新去见大于cx
  1094. if abs(left - (middle - new_area_offset)) > expansion_limit:
  1095. # 增加区间(新区间不包括c,增加了一个偏移kx)
  1096. iter_interval.append([left, middle - new_area_offset])
  1097. expansion_depth -= 1 # 余额减一
  1098. if (
  1099. abs((middle + new_area_offset) - right)
  1100. > expansion_limit
  1101. ):
  1102. iter_interval.append(
  1103. [middle + new_area_offset, right]
  1104. ) # 增加区间
  1105. expansion_depth -= 1
  1106. break # 这个区间迭代完成,跳出返回c
  1107. elif left_zero_c * right_zero_c == 0: # a或者b之间有一个是零点
  1108. if left_zero_c == 0: # a是零点
  1109. middle = left
  1110. if (
  1111. expansion_depth > 0
  1112. and abs((left + new_area_offset) - right)
  1113. > expansion_limit
  1114. ):
  1115. iter_interval.append([left + new_area_offset, right])
  1116. expansion_depth -= 1
  1117. break
  1118. else:
  1119. middle = right # 同上
  1120. if (
  1121. expansion_depth > 0
  1122. and abs(left - (right - new_area_offset))
  1123. > expansion_limit
  1124. ):
  1125. iter_interval.append([left, right - new_area_offset])
  1126. expansion_depth -= 1
  1127. break
  1128. elif left_zero_c * right_zero_c > 0: # q和p都有或都没用零点
  1129. if (
  1130. left_zero_c > 0
  1131. and abs(left - right) < zero_minimum_distance
  1132. ): # 如果ab足够小反围,则认为a和b之间不存在零点
  1133. if allow_extended_calculations:
  1134. # addNews('进入梯度运算')
  1135. middle = self.gradient_calculation(
  1136. y_value, left, right
  1137. )[1]
  1138. if middle is not None:
  1139. break
  1140. middle = None
  1141. break
  1142. iter_interval.append([right, middle]) # 其中一个方向继续迭代,另一个方向加入候选
  1143. right = middle
  1144. elif left_zero_c < 0: # 往一个方向收缩,同时另一个方向增加新的区间
  1145. if (
  1146. expansion_depth > 0
  1147. and abs(middle - right) > expansion_limit
  1148. ):
  1149. iter_interval.append([middle, right])
  1150. expansion_depth -= 1
  1151. right = middle
  1152. elif right_zero_c < 0: # 同上
  1153. if expansion_depth > 0 and abs(left - middle) > expansion_limit:
  1154. iter_interval.append([left, middle])
  1155. expansion_depth -= 1
  1156. left = middle
  1157. if abs(left - right) < accuracy: # a和b足够小,认为找到零点
  1158. middle = (left + right) / 2
  1159. middle_y = self(middle)
  1160. if (
  1161. secondary_verification
  1162. and abs(y_value - middle_y) > secondary_verification_effect
  1163. ):
  1164. middle = None
  1165. break
  1166. except BaseException:
  1167. break
  1168. else: # 证明没有break
  1169. no_break = True
  1170. if middle is None:
  1171. continue # 去除c不存在的选项
  1172. if not no_break:
  1173. middle_list.append(middle)
  1174. else:
  1175. middle_list_deviation.append(middle)
  1176. answer = []
  1177. for i in middle_list:
  1178. self.memore_x.append(i)
  1179. self.memore_y.append(y_value)
  1180. answer.append(f"y={y_value} -> x={i}")
  1181. if return_all:
  1182. for i in middle_list_deviation:
  1183. answer.append(f"(误差)y={y_value} -> x={i}")
  1184. self.memory_answer += answer
  1185. return answer, middle_list
  1186. def calculation(self, x_in):
  1187. answer = []
  1188. for i in x_in:
  1189. try:
  1190. i = float(i)
  1191. y = self(i)
  1192. answer.append(f"x={i} -> y={y}={float(y)}")
  1193. if i not in self.memore_x:
  1194. self.memore_x.append(i)
  1195. self.memore_y.append(y)
  1196. except BaseException: # 捕捉运算错误
  1197. continue
  1198. self.best_value_core()
  1199. self.dataframe = pandas.DataFrame(
  1200. (self.x + self.memore_x, self.y + self.memore_y), index=("x", "y")
  1201. )
  1202. self.memory_answer += answer
  1203. return answer
  1204. def derivative(self, x_value, delta_x=0.1, must=False): # 可导函数求导,不可导函数逼近
  1205. derivatives = self.derivatives
  1206. try:
  1207. delta_x = abs(float(delta_x))
  1208. except BaseException:
  1209. delta_x = 0.1
  1210. try:
  1211. x_value = float(x_value)
  1212. if derivatives is not None and not must: # 导函数法
  1213. derivative_num = derivatives.evalf(subs={self.symbol_x: x_value})
  1214. derivative_method = "导函数求值"
  1215. else:
  1216. x1 = x_value - delta_x / 2
  1217. x2 = x_value + delta_x / 2
  1218. y1 = self(x1)
  1219. y2 = self(x2)
  1220. delta_x = y2 - y1
  1221. derivative_num = delta_x / delta_x
  1222. derivative_method = "逼近法求值"
  1223. except BaseException:
  1224. return None, None
  1225. answer = f"({derivative_method})x:{x_value} -> {derivative_num}"
  1226. return answer, derivative_num
  1227. @plugin_class_loading(get_path(r'template/funcsystem'))
  1228. class ExpProperty(ExpFuncInit, metaclass=ABCMeta):
  1229. def parity(self, precision=False): # 启动round处理
  1230. if not self.have_data_packet:
  1231. self.data_packet(float) # 运行Cul计算
  1232. if len(self.classification_x) != 1:
  1233. need_computing = True # 通过self计算y
  1234. else:
  1235. need_computing = False
  1236. y = self.y.copy()
  1237. x = self.x.copy()
  1238. a = self.start
  1239. b = self.end
  1240. a = -min([abs(a), abs(b)])
  1241. b = -a
  1242. flat = None # 0-偶函数,1-奇函数
  1243. for i in range(len(x)):
  1244. now_x = x[i] # 正项x
  1245. if now_x < a or now_x > b:
  1246. continue # x不在区间内
  1247. try:
  1248. if need_computing:
  1249. now_y = self(now_x)
  1250. else:
  1251. now_y = y[i] # 求得x的y
  1252. if need_computing:
  1253. symmetry_y = self(-now_x)
  1254. else:
  1255. symmetry_y = y[x.index(-now_x)] # 求得-x的y
  1256. if precision:
  1257. now_y = round(now_y, self.accuracy)
  1258. symmetry_y = round(symmetry_y, self.accuracy)
  1259. if symmetry_y == now_y == 0:
  1260. continue
  1261. elif symmetry_y == now_y:
  1262. if flat is None:
  1263. flat = 0
  1264. elif flat == 1:
  1265. raise Exception
  1266. elif symmetry_y == -now_y:
  1267. if flat is None:
  1268. flat = 1
  1269. elif flat == 0:
  1270. raise Exception
  1271. else:
  1272. raise Exception
  1273. except BaseException:
  1274. flat = None
  1275. break
  1276. return flat, [a, b]
  1277. def monotonic(self):
  1278. if not self.have_data_packet:
  1279. self.data_packet(float) # 运行Cul计算
  1280. classification_x = self.classification_x.copy()
  1281. increase_interval = [] # 增区间
  1282. minus_interval = [] # 减区间
  1283. interval = [] # 不增不减
  1284. for i in range(len(classification_x)):
  1285. x_list = classification_x[i]
  1286. y_list = classification_x[i]
  1287. last_x = None
  1288. last_y = None
  1289. start_x = None
  1290. flat = None # 当前研究反围:0-增区间,1-减区间,2-不增不减
  1291. for a in range(len(x_list)):
  1292. now_x = x_list[a] # 正项x
  1293. now_y = y_list[a] # 正项y
  1294. if start_x is None:
  1295. start_x = now_x
  1296. else:
  1297. if last_y > now_y: # 减区间
  1298. if flat is None or flat == 1: # 减区间
  1299. pass
  1300. elif flat == 0: # 增区间
  1301. increase_interval.append((start_x, last_x))
  1302. start_x = last_x
  1303. elif flat == 2:
  1304. interval.append((start_x, last_x))
  1305. start_x = last_x
  1306. flat = 1
  1307. elif last_y < now_y: # 增区间
  1308. if flat is None or flat == 0: # 增区间
  1309. pass
  1310. elif flat == 1: # 减区间
  1311. minus_interval.append((start_x, last_x))
  1312. start_x = last_x
  1313. elif flat == 2:
  1314. interval.append((start_x, last_x))
  1315. start_x = last_x
  1316. flat = 0
  1317. else: # 水平区间
  1318. if flat is None or flat == 2:
  1319. pass
  1320. elif flat == 1: # 减区间
  1321. minus_interval.append((start_x, last_x))
  1322. start_x = last_x
  1323. elif flat == 0: # 增区间
  1324. increase_interval.append((start_x, last_x))
  1325. start_x = last_x
  1326. flat = 2
  1327. last_x = now_x
  1328. last_y = now_y
  1329. if flat == 2:
  1330. interval.append((start_x, last_x))
  1331. elif flat == 1: # 减区间
  1332. minus_interval.append((start_x, last_x))
  1333. elif flat == 0: # 增区间
  1334. increase_interval.append((start_x, last_x))
  1335. return increase_interval, minus_interval, interval
  1336. def property_prediction(
  1337. self, output_prompt=lambda x: x, return_all=False, accuracy=None
  1338. ):
  1339. try:
  1340. accuracy = float(accuracy)
  1341. except BaseException:
  1342. accuracy = None
  1343. answer = []
  1344. parity = self.parity()
  1345. monotonic = self.monotonic()
  1346. periodic = self.periodic(output_prompt, accuracy)
  1347. symmetry_axis = self.symmetry_axis(output_prompt, accuracy)
  1348. symmetry_center = self.symmetry_center(output_prompt, accuracy)
  1349. if parity[0] == 1:
  1350. answer.append(f"奇函数 区间:[{parity[1][0]},{parity[1][0]}]")
  1351. elif parity[0] == 0:
  1352. answer.append(f"偶函数 区间:[{parity[1][0]},{parity[1][0]}]")
  1353. for i in monotonic[0]:
  1354. answer.append(f"增区间:[{i[0]},{i[1]}]")
  1355. for i in monotonic[1]:
  1356. answer.append(f"减区间:[{i[0]},{i[1]}]")
  1357. for i in monotonic[2]:
  1358. answer.append(f"水平区间:[{i[0]},{i[1]}]")
  1359. if self.derivatives:
  1360. answer.append(f"导函数:{self.derivatives}")
  1361. if periodic[0] is not None:
  1362. answer.append(f"最小正周期:{periodic[0]}")
  1363. if symmetry_axis[0] is not None:
  1364. answer.append(f"对称轴:x={symmetry_axis[0]}")
  1365. if symmetry_center[0] is not None:
  1366. answer.append(f"对称中心:{symmetry_center[0]}")
  1367. if return_all:
  1368. try:
  1369. for i in periodic[1][1:]:
  1370. answer.append(f"可能的最小正周期:{i}")
  1371. except BaseException:
  1372. pass
  1373. try:
  1374. for i in symmetry_axis[1][1:]:
  1375. answer.append(f"可能的对称轴:{i}")
  1376. except BaseException:
  1377. pass
  1378. try:
  1379. for i in symmetry_center[1][1:]:
  1380. answer.append(f"可能的对称中心:{i}")
  1381. except BaseException:
  1382. pass
  1383. return answer
  1384. def periodic(self, output_prompt=lambda x: x, accuracy=None): # 计算周期
  1385. if not tkinter.messagebox.askokcancel("提示", f"计算周期需要一定时间,是否执行?(计算过程程序可能无响应)"):
  1386. return None, [] # 无结果
  1387. if not self.have_data_packet:
  1388. self.data_packet(float)
  1389. possible_cycle_list = [] # 可能的周期
  1390. start = self.start
  1391. end = self.end
  1392. if accuracy is not None:
  1393. span = accuracy
  1394. else:
  1395. span = abs(start - end) / 20
  1396. output_prompt("正在预测可能的周期")
  1397. while start <= end:
  1398. try:
  1399. y = self(start)
  1400. x_list = self.dichotomy(y)[1]
  1401. output_prompt("迭代运算...")
  1402. # print(x_list)
  1403. possible_cycle = []
  1404. for o_x in x_list:
  1405. a = round(abs(o_x - start), self.accuracy)
  1406. if a == 0:
  1407. start += span
  1408. continue
  1409. if a:
  1410. possible_cycle.append(round(a, self.accuracy))
  1411. possible_cycle_list.extend(list(set(possible_cycle))) # 不是append
  1412. except BaseException:
  1413. pass
  1414. start += span
  1415. possible_cycle = [] # a的可能列表
  1416. max_count = 0
  1417. output_prompt("正在筛选结果")
  1418. for i in list(set(possible_cycle_list)):
  1419. count = possible_cycle_list.count(i)
  1420. if count > max_count:
  1421. possible_cycle = [i]
  1422. max_count = count
  1423. elif count == max_count:
  1424. possible_cycle.append(i)
  1425. try:
  1426. possible_cycle.sort()
  1427. output_prompt("计算完毕")
  1428. return possible_cycle[0], possible_cycle
  1429. except BaseException:
  1430. output_prompt("无周期")
  1431. return None, [] # 无结果
  1432. def symmetry_axis(self, output_prompt=lambda x: x, accuracy=None): # 计算对称轴
  1433. if not tkinter.messagebox.askokcancel("提示", f"计算对称轴需要一定时间,是否执行?(计算过程程序可能无响应)"):
  1434. return None, [] # 无结果
  1435. if not self.have_data_packet:
  1436. self.data_packet()
  1437. possible_symmetry_axis_list = [] # 可能的对称轴
  1438. start = self.start
  1439. end = self.end
  1440. if accuracy is not None:
  1441. span = accuracy
  1442. else:
  1443. span = abs(start - end) / 20
  1444. output_prompt("正在预测对称轴")
  1445. while start <= end:
  1446. try:
  1447. y = self(start)
  1448. x_list = self.dichotomy(y)[1]
  1449. output_prompt("迭代运算...")
  1450. # print(x_list)
  1451. possible_symmetry_axis = []
  1452. for o_x in x_list:
  1453. a = (o_x + start) / 2
  1454. if a:
  1455. possible_symmetry_axis.append(round(a, self.accuracy))
  1456. possible_symmetry_axis_list.extend(list(set(possible_symmetry_axis)))
  1457. except BaseException:
  1458. pass
  1459. start += span
  1460. possible_symmetry_axis = [] # a的可能列表
  1461. c = 0
  1462. output_prompt("正在筛选结果")
  1463. for i in list(set(possible_symmetry_axis_list)):
  1464. n_c = possible_symmetry_axis_list.count(i)
  1465. if n_c > c:
  1466. possible_symmetry_axis = [i]
  1467. c = n_c
  1468. elif n_c == c:
  1469. possible_symmetry_axis.append(i)
  1470. try:
  1471. possible_symmetry_axis.sort() #
  1472. output_prompt("计算完毕")
  1473. return possible_symmetry_axis[0], possible_symmetry_axis
  1474. except BaseException:
  1475. output_prompt("无对称轴")
  1476. return None, [] # 无结果
  1477. def symmetry_center(self, output_prompt=lambda x: x, accuracy=None): # 计算对称中心
  1478. if not tkinter.messagebox.askokcancel("提示", f"计算对称中心需要一定时间,是否执行?(计算过程程序可能无响应)"):
  1479. return None, [] # 无结果
  1480. if not self.have_data_packet:
  1481. self.data_packet(float)
  1482. coordinate_points = [] # 可能的对称轴
  1483. start = self.start
  1484. end = self.end
  1485. output_prompt("正在计算坐标点")
  1486. if accuracy is not None:
  1487. span = accuracy
  1488. else:
  1489. span = 1
  1490. while start <= end:
  1491. try:
  1492. y = self(start)
  1493. x = start
  1494. coordinate_points.append((x, y))
  1495. except BaseException:
  1496. pass
  1497. start += span
  1498. possible_center_list = []
  1499. output_prompt("正在预测对称中心")
  1500. for i in coordinate_points:
  1501. for o in coordinate_points:
  1502. x = round((i[0] + o[0]) / 2, self.accuracy)
  1503. y = round((i[1] + o[1]) / 2, self.accuracy)
  1504. if i == o:
  1505. continue
  1506. possible_center_list.append((x, y))
  1507. possible_center = [] # a的可能列表
  1508. max_count = 0
  1509. output_prompt("正在筛选结果")
  1510. for i in list(set(possible_center_list)):
  1511. count = possible_center_list.count(i)
  1512. if count > max_count:
  1513. possible_center = [i]
  1514. max_count = count
  1515. elif count == max_count:
  1516. possible_center.append(i)
  1517. try:
  1518. if max_count < 5:
  1519. raise Exception
  1520. output_prompt("计算完毕")
  1521. possible_center.sort() #
  1522. return possible_center[int(len(possible_center) / 2)], possible_center
  1523. except BaseException:
  1524. output_prompt("无对称中心")
  1525. return None, [] # 无结果
  1526. @plugin_class_loading(get_path(r'template/funcsystem'))
  1527. class ExpCheck(ExpFuncInit, metaclass=ABCMeta):
  1528. def check_monotonic(
  1529. self, parameters, output_prompt=lambda x: x, accuracy=None
  1530. ): # 检查单调性
  1531. result = True # 预测结果
  1532. try:
  1533. parameters = parameters.split(",")
  1534. start = float(parameters[0])
  1535. end = float(parameters[1])
  1536. flat = int(parameters[2]) # 当前研究反围:0-增区间,1-减区间,2-不增不减
  1537. except BaseException:
  1538. return False, ""
  1539. if start > end:
  1540. start, end = end, start
  1541. last_y = None
  1542. if accuracy is not None:
  1543. span = accuracy
  1544. else:
  1545. span = self.span
  1546. while start <= end:
  1547. try:
  1548. output_prompt("迭代运算...")
  1549. now_y = round(self(start), self.accuracy)
  1550. except BaseException:
  1551. start += span
  1552. continue
  1553. if last_y is None:
  1554. continue
  1555. if flat == 0 and last_y > now_y: # 增区间,o_y不小于y
  1556. result = False
  1557. break
  1558. elif flat == 1 and last_y < now_y: # 减小区间,o_y不小于y
  1559. result = False
  1560. break
  1561. elif flat == 2 and last_y != now_y:
  1562. result = False
  1563. break
  1564. last_y = now_y
  1565. start += span
  1566. monotonic_key = {0: "单调递增", 1: "单调递减", 2: "平行"}
  1567. result_key = {True: "成立", False: "不成立"}
  1568. return (
  1569. result,
  1570. f"{self}在[{parameters[0]},{parameters[1]}]{monotonic_key[flat]}{result_key[result]}",
  1571. )
  1572. def check_periodic(
  1573. self, parameters, output_prompt=lambda x: x, accuracy=None
  1574. ): # 检查周期性
  1575. result = True
  1576. try:
  1577. parameters = float(parameters)
  1578. except BaseException:
  1579. return False, ""
  1580. start = self.start
  1581. end = self.end
  1582. if accuracy is not None:
  1583. span = accuracy
  1584. else:
  1585. span = self.span
  1586. while start <= end:
  1587. try:
  1588. output_prompt("迭代运算...")
  1589. now_y = round(self(start), self.accuracy)
  1590. last_y = round(self(start + parameters), self.accuracy)
  1591. if now_y != last_y:
  1592. result = False
  1593. except BaseException:
  1594. pass
  1595. start += span
  1596. result_key = {True: "是", False: "不是"}
  1597. return result, f"{self}的周期{result_key[result]}{parameters}"
  1598. def check_symmetry_axis(
  1599. self, parameters, output_prompt=lambda x: x, accuracy=None
  1600. ): # 检查对称轴
  1601. result = True
  1602. try:
  1603. parameters = 2 * float(parameters)
  1604. except BaseException:
  1605. return False, ""
  1606. start = self.start
  1607. end = self.end
  1608. if accuracy is not None:
  1609. span = accuracy
  1610. else:
  1611. span = self.span
  1612. while start <= end:
  1613. try:
  1614. output_prompt("迭代运算...")
  1615. now_y = round(self(start), self.accuracy)
  1616. last_y = round(self(parameters - start), self.accuracy)
  1617. if now_y != last_y:
  1618. result = False
  1619. except BaseException:
  1620. pass
  1621. start += span
  1622. result_key = {True: "是", False: "不是"}
  1623. return result, f"{self}的对称轴{result_key[result]}{parameters}"
  1624. def check_symmetry_center(
  1625. self, parameters_input, output_prompt=lambda x: x, accuracy=None
  1626. ): # 检查对称中心
  1627. result = True
  1628. try:
  1629. parameters = []
  1630. for i in parameters_input.split(","):
  1631. parameters.append(float(i))
  1632. except BaseException:
  1633. return False, ""
  1634. start = self.start
  1635. end = self.end
  1636. if accuracy is not None:
  1637. span = accuracy
  1638. else:
  1639. span = self.span
  1640. while start <= end:
  1641. try:
  1642. output_prompt("迭代运算...")
  1643. now_y = round(self(start), self.accuracy)
  1644. last_y = round(self(2 * parameters[0] - start), self.accuracy)
  1645. if round((now_y + last_y) / 2, self.accuracy) != parameters[1]:
  1646. result = False
  1647. except BaseException:
  1648. pass
  1649. start += span
  1650. result_key = {True: "是", False: "不是"}
  1651. return result, f"{self}的对称中心{result_key[result]}{parameters}"
  1652. @plugin_class_loading(get_path(r'template/funcsystem'))
  1653. class ExpMemory(ExpFuncInit, metaclass=ABCMeta):
  1654. def hide_or_show(self): # 记忆数据显示和隐藏
  1655. if self.have_prediction:
  1656. if tkinter.messagebox.askokcancel("提示", f"是否显示{self}的记忆数据?"):
  1657. # addNews('记忆显示完毕')
  1658. self.have_prediction = False
  1659. else:
  1660. if tkinter.messagebox.askokcancel("提示", f"是否隐藏{self}的记忆数据?"):
  1661. # addNews('记忆隐藏完毕')
  1662. self.have_prediction = True
  1663. def clean_memory(self):
  1664. self.memore_x = []
  1665. self.memore_y = []
  1666. self.memory_answer = []
  1667. def get_memory(self):
  1668. if self.have_prediction:
  1669. return [], []
  1670. return self.memore_x, self.memore_y
  1671. @plugin_class_loading(get_path(r'template/funcsystem'))
  1672. class ExpFuncSon:
  1673. def __init__(
  1674. self, func, style, start=-10, end=10, span=0.1, accuracy=2, a_default=1
  1675. ):
  1676. self.symbol_x = sympy.Symbol("x")
  1677. named_domain = {
  1678. "a": a_default,
  1679. "x": self.symbol_x,
  1680. "Pi": sympy.pi,
  1681. "e": sympy.E,
  1682. "log": sympy.log,
  1683. "sin": sympy.sin,
  1684. "cos": sympy.cos,
  1685. "tan": sympy.tan,
  1686. "cot": lambda x: 1 / sympy.tan(x),
  1687. "csc": lambda x: 1 / sympy.sin(x),
  1688. "sec": lambda x: 1 / sympy.cos(x),
  1689. "sinh": sympy.sinh,
  1690. "cosh": sympy.cosh,
  1691. "tanh": sympy.tanh,
  1692. "asin": sympy.asin,
  1693. "acos": sympy.acos,
  1694. "atan": sympy.atan,
  1695. "abs": abs,
  1696. } # 这个是函数命名域
  1697. self.func = eval(func.replace(" ", ""), named_domain) # 函数解析式
  1698. self.func_str = func.replace(" ", "")
  1699. # 函数基本信息
  1700. self.func_name = f"y={func} a={a_default}" # 这个是函数名字
  1701. self.style = style # 绘制样式
  1702. # 数据辨析
  1703. try:
  1704. start = float(start)
  1705. end = float(end)
  1706. if start > end: # 使用float确保输入是数字,否则诱发ValueError
  1707. start, end = end, start
  1708. span = abs(float(span))
  1709. start = (start // span) * span # 确保start可以恰好被kd整除
  1710. end = (end // span + 1) * span
  1711. accuracy = abs(int(accuracy))
  1712. if accuracy >= 3:
  1713. accuracy = 3
  1714. except ValueError:
  1715. start, end, span, accuracy = -10, 10, 0.1, 2 # 保底设置
  1716. # 基本数据存储
  1717. self.accuracy = accuracy
  1718. self.start = start
  1719. self.end = end
  1720. self.span = span
  1721. # x和y数据存储
  1722. self.x = []
  1723. self.y = []
  1724. self.y_real = []
  1725. self.classification_x = [[]]
  1726. self.classification_y = [[]]
  1727. self.have_data_packet = False
  1728. def __call__(self, x):
  1729. return self.func.evalf(subs={self.symbol_x: x})
  1730. def __str__(self):
  1731. return f"{self.func_name} {self.start, self.end, self.span}"
  1732. def data_packet(self, number_type=float):
  1733. if self.have_data_packet:
  1734. return self.x, self.y, self.func_name, self.style
  1735. # 混合存储
  1736. self.y = []
  1737. self.y_real = []
  1738. self.x = []
  1739. self.classification_x = [[]]
  1740. self.classification_y = [[]]
  1741. classification_reason = [100]
  1742. last_y = None
  1743. last_monotonic = None # 单调性 0-增,1-减
  1744. now_monotonic = 1
  1745. try:
  1746. now_x = int(self.start)
  1747. while now_x <= int(self.end): # 因为range不接受小数
  1748. group_score = 0
  1749. balance = 1
  1750. try:
  1751. accuracy_x = round(now_x, self.accuracy)
  1752. now_y = number_type(self(accuracy_x)) # 数字处理方案
  1753. accuracy_y = round(now_y, self.accuracy)
  1754. if last_y is not None and last_y > now_y:
  1755. now_monotonic = 1
  1756. elif last_y is not None and last_y < now_y:
  1757. now_monotonic = 0
  1758. elif last_y is not None and last_y == now_y:
  1759. try:
  1760. middle_y = self(round(accuracy_x - 0.5 * self.span))
  1761. if middle_y == last_y == now_y: # 真实平衡
  1762. balance = 2
  1763. elif (
  1764. abs(middle_y - last_y) >= 10 * self.span
  1765. or abs(middle_y - now_y) >= 10 * self.span
  1766. ):
  1767. balance = 3
  1768. group_score += 5
  1769. except BaseException:
  1770. balance = 4
  1771. group_score += 9
  1772. now_monotonic = 2
  1773. if last_y is not None and last_monotonic != now_monotonic:
  1774. if (last_y * now_y) < 0:
  1775. group_score += 5
  1776. elif abs(last_y - now_y) >= (10 * self.span):
  1777. group_score += 5
  1778. if group_score >= 5 and (now_monotonic != 2 or balance != 2):
  1779. classification_reason.append(group_score)
  1780. self.classification_x.append([])
  1781. self.classification_y.append([])
  1782. last_monotonic = now_monotonic
  1783. self.x.append(accuracy_x) # 四舍五入减少计算量
  1784. self.y.append(now_y) # 不四舍五入
  1785. self.y_real.append(accuracy_y) # 四舍五入(用于求解最值)
  1786. self.classification_x[-1].append(accuracy_x)
  1787. self.classification_y[-1].append(now_y)
  1788. last_y = now_y
  1789. except BaseException:
  1790. classification_reason.append(0)
  1791. self.classification_x.append([])
  1792. self.classification_y.append([])
  1793. now_x += self.span
  1794. except (TypeError, IndexError, ValueError):
  1795. pass
  1796. new_classification_x = []
  1797. new_classification_y = []
  1798. classification_reason.append(99)
  1799. must_forward = False
  1800. for i in range(len(self.classification_x)): # 去除只有单个的组群
  1801. if len(self.classification_x[i]) <= 1 and not must_forward: # 检测到有单个群组
  1802. front_reason = classification_reason[i] # 前原因
  1803. back_reason = classification_reason[i + 1] # 后原因
  1804. if front_reason < back_reason: # 前原因小于后原因,连接到前面
  1805. try:
  1806. new_classification_x[-1] += self.classification_x[i]
  1807. new_classification_y[-1] += self.classification_y[i]
  1808. except BaseException: # 按道理不应该出现这个情况
  1809. new_classification_x.append(self.classification_x[i])
  1810. new_classification_y.append(self.classification_y[i])
  1811. else:
  1812. new_classification_x.append(self.classification_x[i])
  1813. new_classification_y.append(self.classification_y[i])
  1814. must_forward = True
  1815. else:
  1816. if not must_forward:
  1817. new_classification_x.append(self.classification_x[i])
  1818. new_classification_y.append(self.classification_y[i])
  1819. else:
  1820. new_classification_x[-1] += self.classification_x[i]
  1821. new_classification_y[-1] += self.classification_y[i]
  1822. must_forward = False
  1823. self.classification_x = new_classification_x
  1824. self.classification_y = new_classification_y
  1825. self.have_data_packet = True
  1826. return self.x, self.y, self.func_name, self.style
  1827. def get_plot_data(self):
  1828. if not self.have_data_packet:
  1829. self.data_packet()
  1830. return (
  1831. self.classification_x,
  1832. self.classification_y,
  1833. self.func_name,
  1834. self.style,
  1835. )