1
0

template.py 77 KB

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