template.py 76 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971
  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. else:
  719. self.son_list = []
  720. self.func_name = f"{name}:y={func} a={a_default})" # 这个是函数名字
  721. def __call__(self, x):
  722. return self.func.subs({self.symbol_x: x})
  723. def __str__(self):
  724. return f"{self.func_name} {self.start, self.end, self.span}"
  725. @abstractmethod
  726. def best_value_core(self):
  727. pass
  728. @plugin_class_loading(get_path(r'template/funcsystem'))
  729. class ExpDataPacket(ExpFuncInit, metaclass=ABCMeta):
  730. def data_packet(self, number_type=float):
  731. if self.have_data_packet:
  732. return self.x, self.y, self.func_name, self.style
  733. # 混合存储
  734. self.y = []
  735. self.y_real = []
  736. self.x = []
  737. self.xy_sheet = []
  738. self.classification_x = [[]]
  739. self.classification_y = [[]]
  740. classification_reason = [100]
  741. last_y = None
  742. last_monotonic = None # 单调性 0-增,1-减
  743. now_monotonic = 1
  744. try:
  745. now_x = int(self.start)
  746. while now_x <= int(self.end): # 因为range不接受小数
  747. group_score = 0
  748. balance = 1
  749. try:
  750. accuracy_x = round(now_x, self.accuracy)
  751. now_y = number_type(self(accuracy_x)) # 数字处理方案
  752. accuracy_y = round(now_y, self.accuracy)
  753. if last_y is not None and last_y > now_y:
  754. now_monotonic = 1
  755. elif last_y is not None and last_y < now_y:
  756. now_monotonic = 0
  757. elif last_y is not None and last_y == now_y:
  758. try:
  759. middle_y = self(round(accuracy_x - 0.5 * self.span))
  760. if middle_y == last_y == now_y: # 真实平衡
  761. balance = 2
  762. elif (
  763. abs(middle_y - last_y) >= 10 * self.span
  764. or abs(middle_y - now_y) >= 10 * self.span
  765. ):
  766. balance = 3
  767. group_score += 5
  768. except TypeError:
  769. balance = 4
  770. group_score += 9
  771. now_monotonic = 2
  772. if last_y is not None and last_monotonic != now_monotonic:
  773. if (last_y * now_y) < 0:
  774. group_score += 5
  775. elif abs(last_y - now_y) >= (10 * self.span):
  776. group_score += 5
  777. if group_score >= 5 and (now_monotonic != 2 or balance != 2):
  778. classification_reason.append(group_score)
  779. self.classification_x.append([])
  780. self.classification_y.append([])
  781. last_monotonic = now_monotonic
  782. self.x.append(accuracy_x) # 四舍五入减少计算量
  783. self.y.append(now_y) # 不四舍五入
  784. self.y_real.append(accuracy_y) # 四舍五入(用于求解最值)
  785. self.xy_sheet.append(f"x:{accuracy_x},y:{accuracy_y}")
  786. self.classification_x[-1].append(accuracy_x)
  787. self.classification_y[-1].append(now_y)
  788. last_y = now_y
  789. except BaseException as e:
  790. logging.debug(str(e))
  791. classification_reason.append(0)
  792. self.classification_x.append([])
  793. self.classification_y.append([])
  794. now_x += self.span
  795. except (TypeError, IndexError, ValueError):
  796. pass
  797. new_classification_x = []
  798. new_classification_y = []
  799. classification_reason.append(99)
  800. must_forward = False
  801. for i in range(len(self.classification_x)): # 去除只有单个的组群
  802. if len(self.classification_x[i]) <= 1 and not must_forward: # 检测到有单个群组
  803. front_reason = classification_reason[i] # 前原因
  804. back_reason = classification_reason[i + 1] # 后原因
  805. if front_reason < back_reason: # 前原因小于后原因,连接到前面
  806. try:
  807. new_classification_x[-1] += self.classification_x[i]
  808. new_classification_y[-1] += self.classification_y[i]
  809. except IndexError: # 按道理不应该出现这个情况
  810. new_classification_x.append(self.classification_x[i])
  811. new_classification_y.append(self.classification_y[i])
  812. else:
  813. new_classification_x.append(self.classification_x[i])
  814. new_classification_y.append(self.classification_y[i])
  815. must_forward = True
  816. else:
  817. if not must_forward:
  818. new_classification_x.append(self.classification_x[i])
  819. new_classification_y.append(self.classification_y[i])
  820. else:
  821. new_classification_x[-1] += self.classification_x[i]
  822. new_classification_y[-1] += self.classification_y[i]
  823. must_forward = False
  824. self.classification_x = new_classification_x
  825. self.classification_y = new_classification_y
  826. self.have_data_packet = True
  827. self.dataframe = pandas.DataFrame((self.x, self.y), index=("x", "y"))
  828. self.best_value_core()
  829. return self.x, self.y, self.func_name, self.style
  830. @plugin_class_loading(get_path(r'template/funcsystem'))
  831. class ExpBestValue(ExpFuncInit, metaclass=ABCMeta):
  832. def best_value_core(self): # 计算最值和极值点
  833. # 使用ya解决了因计算器误差而没计算到的最值,但是同时本不是最值的与最值相近的数字也被当为了最值,所以使用群组击破
  834. if not self.have_data_packet:
  835. self.data_packet() # 检查Cul的计算
  836. if len(self.classification_x) != 1: # 没有计算的必要
  837. if self.best_r is None:
  838. self.best_r = not tkinter.messagebox.askokcancel(
  839. "建议不计算最值", f"{self}的最值计算不精确,函数可能无最值,是否不计算最值"
  840. )
  841. if not self.best_r:
  842. pass
  843. return self.max_x, self.max_y, self.min_x, self.min_y
  844. y = self.y_real + self.memore_y # x和y数据对齐(因为是加法,所以y的修改不影响self.__ya)
  845. _y = self.y + self.memore_y
  846. x = self.x + self.memore_x
  847. max_y = max(y)
  848. min_y = min(y)
  849. max_x = find_x_by_y(x.copy(), y, max_y)
  850. min_x = find_x_by_y(x.copy(), y, min_y)
  851. # 处理最大值极值点重复
  852. max_x = sorted(list(set(max_x))) # 处理重复
  853. groups_list = []
  854. last_x = None
  855. flat = False
  856. can_handle = max_x.copy() # 可处理列表
  857. for i in range(len(max_x)): # 迭代选择
  858. now_x = max_x[i]
  859. if last_x is None or abs(now_x - last_x) >= 1: # 1-连续系数
  860. flat = False
  861. else:
  862. if flat: # 加入群组
  863. groups_list[-1].append(now_x)
  864. else: # 新键群组
  865. groups_list.append([last_x, now_x])
  866. del can_handle[can_handle.index(last_x)]
  867. flat = True
  868. del can_handle[can_handle.index(now_x)] # 删除可处理列表
  869. last_x = now_x
  870. for i in groups_list: # 逐个攻破群组
  871. groups_y = [] # 群组中x的y值
  872. for x_in_groups in i:
  873. num = x.index(x_in_groups)
  874. groups_y.append(_y[num]) # 找到对应y值
  875. groups_x = find_x_by_y(i, groups_y, max(groups_y))
  876. groups_max_x = groups_x[int(len(groups_x) / 2)]
  877. can_handle.append(groups_max_x) # 取中间个
  878. self.max_y = max_y
  879. self.max_x = can_handle
  880. # 处理最小值极值点重复
  881. min_x = sorted(list(set(min_x))) # 处理重复
  882. groups_list = []
  883. last_x = None
  884. flat = False
  885. can_handle = min_x.copy() # 可处理列表
  886. for i in range(len(min_x)): # 迭代选择
  887. now_x = min_x[i]
  888. if last_x is None or abs(now_x - last_x) >= 1: # 1-连续系数
  889. flat = False
  890. else:
  891. if flat: # 加入群组
  892. groups_list[-1].append(now_x)
  893. else: # 新键群组
  894. groups_list.append([last_x, now_x])
  895. del can_handle[can_handle.index(last_x)]
  896. flat = True
  897. del can_handle[can_handle.index(now_x)] # 删除可处理列表
  898. last_x = now_x
  899. for i in groups_list: # 逐个攻破群组
  900. groups_y = [] # 群组中x的y值
  901. for x_in_groups in i:
  902. num = x.index(x_in_groups)
  903. groups_y.append(_y[num]) # 找到对应y值
  904. groups_x = find_x_by_y(i, groups_y, min(groups_y))
  905. groups_max_x = groups_x[int(len(groups_x) / 2)]
  906. can_handle.append(groups_max_x) # 取中间个
  907. self.min_y = min_y
  908. self.min_x = can_handle
  909. return self.max_x, self.max_y, self.min_x, self.min_y
  910. def best_value(self):
  911. return self.max_x, self.max_y, self.min_x, self.min_y
  912. @plugin_class_loading(get_path(r'template/funcsystem'))
  913. class ExpComputing(ExpFuncInit, metaclass=ABCMeta):
  914. def sympy_calculation(self, y_value): # 利用Sympy解方程
  915. try:
  916. equation = self.func - float(y_value)
  917. result_list = sympy.solve(equation, self.symbol_x)
  918. answer = []
  919. for x in result_list:
  920. self.memore_x.append(x) # 可能需要修复成float(x)
  921. self.memore_y.append(y_value)
  922. answer.append(f"y={y_value} -> x={x}")
  923. return answer, result_list
  924. except ValueError:
  925. return [], []
  926. def gradient_calculation(self, y_value, start, end, max_iter=100, accuracy=0.00001):
  927. try:
  928. y_value = float(y_value)
  929. start = float(start)
  930. end = float(end)
  931. except ValueError:
  932. return "", None
  933. try:
  934. max_iter = int(max_iter)
  935. accuracy = float(accuracy)
  936. except ValueError:
  937. max_iter = 100
  938. accuracy = 0.00001
  939. left = start
  940. right = end
  941. left_history = []
  942. right_history = []
  943. middle_history = None
  944. contraction_direction = 0 # 收缩方向1=a往b,2=b往a,0=未知
  945. actual_monotony = 0 # 增or减
  946. for i in range(max_iter):
  947. if left > right:
  948. left, right = right, left # a是小的数字,b是大的数字,c是中间
  949. left_history.append(left) # 赋值a的回退值
  950. right_history.append(right)
  951. middle = (left + right) / 2
  952. middle_y = self(middle)
  953. # 增减预测
  954. if abs(middle_y - y_value) < accuracy: # 数据计算完成
  955. break
  956. elif middle_y < y_value: # 预测增还是减:_c移动到y_in需要增还是间
  957. future_monotony = 1 # 增
  958. else:
  959. future_monotony = 0 # 减
  960. try: # 当前是增还是减
  961. if middle_history == middle_y: # 恰好关于了原点对称
  962. pass # 保持不变
  963. elif middle_history < middle_y:
  964. actual_monotony = 1 # 增
  965. else:
  966. actual_monotony = 0 # 减
  967. except TypeError:
  968. contraction_direction = 1
  969. actual_monotony = future_monotony
  970. middle_history = middle_y
  971. # 开始行动
  972. if future_monotony == actual_monotony: # 实际和预测一样,保持相同执行方案
  973. if contraction_direction == 1: # a往b方向收缩
  974. left = middle
  975. else:
  976. right = middle
  977. else:
  978. if contraction_direction == 1: # 收缩方向相反
  979. left = left_history[-2]
  980. right = middle
  981. contraction_direction = 0
  982. else:
  983. left = middle
  984. right = right_history[-2]
  985. contraction_direction = 1
  986. else:
  987. return "", None
  988. self.memore_x.append(middle)
  989. self.memore_y.append(y_value)
  990. self.memory_answer.append(f"y={y_value} -> x={middle}")
  991. print(f"y={y_value} -> x={middle}", middle)
  992. return f"y={y_value} -> x={middle}", middle
  993. def dichotomy(
  994. self,
  995. y_value,
  996. max_iter=100,
  997. accuracy=0.0001,
  998. best_value_starting_offset=0.1,
  999. zero_minimum_distance=0.5,
  1000. allow_original_value=False,
  1001. allow_extended_calculations=True,
  1002. expansion_depth=1000,
  1003. expansion_limit=0.1,
  1004. new_area_offset=0.1,
  1005. secondary_verification=False,
  1006. secondary_verification_effect=None,
  1007. return_all=False,
  1008. ):
  1009. # y_in输入的参数,k最大迭代数,r_Cul允许使用原来的数值,d精度,ky最值允许偏移量,kx新区间偏移量,cx扩张限制,dx两零点的最小范围,deep扩张深度
  1010. # H_Cul允许扩展计算,f_On开启二级验证,f二级验证效果
  1011. if secondary_verification_effect is None:
  1012. secondary_verification_effect = accuracy
  1013. try: # 参数处理
  1014. allow_original_value = to_bool(allow_original_value)
  1015. allow_extended_calculations = to_bool(allow_extended_calculations, True)
  1016. secondary_verification = to_bool(secondary_verification)
  1017. max_iter = abs(int(max_iter))
  1018. accuracy = abs(float(accuracy))
  1019. best_value_starting_offset = abs(float(best_value_starting_offset))
  1020. new_area_offset = abs(float(new_area_offset))
  1021. expansion_limit = abs(float(expansion_limit))
  1022. zero_minimum_distance = abs(float(zero_minimum_distance))
  1023. expansion_depth = abs(int(expansion_depth))
  1024. secondary_verification_effect = abs(float(secondary_verification_effect))
  1025. except (ValueError, TypeError):
  1026. allow_original_value = False
  1027. allow_extended_calculations = True
  1028. secondary_verification = False
  1029. max_iter = 100
  1030. accuracy = 0.0001
  1031. best_value_starting_offset = 0.1
  1032. new_area_offset = 0.1
  1033. expansion_limit = 0.5
  1034. zero_minimum_distance = 0.5
  1035. expansion_depth = 100
  1036. secondary_verification_effect = accuracy
  1037. if not self.have_data_packet:
  1038. self.data_packet(float)
  1039. x = self.x + self.memore_x
  1040. y = self.y + self.memore_x
  1041. try:
  1042. y_value = float(y_value)
  1043. except ValueError:
  1044. return [], []
  1045. try:
  1046. if (
  1047. y_value < self.min_y - best_value_starting_offset
  1048. or y_value > self.max_y + best_value_starting_offset
  1049. ):
  1050. return [], [] # 返回空值
  1051. if allow_original_value and y_value in y: # 如果已经计算过
  1052. num = y.index(y_value)
  1053. return x[num]
  1054. except BaseException as e:
  1055. logging.warning(str(e))
  1056. iter_interval = [[self.start, self.end]] # 准备迭代的列表
  1057. middle_list = []
  1058. middle_list_deviation = []
  1059. for interval in iter_interval:
  1060. left = interval[0]
  1061. right = interval[1]
  1062. middle = None
  1063. no_break = False
  1064. for i in range(max_iter): # 限定次数的迭代
  1065. try:
  1066. if left > right:
  1067. left, right = right, left # a是小的数字,b是大的数字,c是中间
  1068. if left == right: # 如果相等,作废
  1069. middle = None
  1070. break
  1071. left_y = self(left) - y_value # 计算a
  1072. right_y = self(right) - y_value # 计算b
  1073. middle = (left + right) / 2 # 计算c
  1074. try:
  1075. middle_y = self(middle) - y_value # 计算c
  1076. except TypeError:
  1077. if expansion_depth > 0: # 尝试向两边扩张,前提是有deep余额(扩张限制)而且新去见大于cx
  1078. if abs(left - (middle - new_area_offset)) > expansion_limit:
  1079. # 增加区间(新区间不包括c,增加了一个偏移kx)
  1080. iter_interval.append([left, middle - new_area_offset])
  1081. expansion_depth -= 1 # 余额减一
  1082. if (
  1083. abs((middle + new_area_offset) - right)
  1084. > expansion_limit
  1085. ):
  1086. iter_interval.append(
  1087. [middle + new_area_offset, right]
  1088. ) # 增加区间
  1089. expansion_depth -= 1
  1090. middle = None
  1091. break
  1092. left_zero_c = left_y * middle_y # a,c之间零点
  1093. right_zero_c = right_y * middle_y # b,c之间零点
  1094. if middle_y == 0: # 如果c就是零点
  1095. if expansion_depth > 0: # 尝试向两边扩张,前提是有deep余额(扩张限制)而且新去见大于cx
  1096. if abs(left - (middle - new_area_offset)) > expansion_limit:
  1097. # 增加区间(新区间不包括c,增加了一个偏移kx)
  1098. iter_interval.append([left, middle - new_area_offset])
  1099. expansion_depth -= 1 # 余额减一
  1100. if (
  1101. abs((middle + new_area_offset) - right)
  1102. > expansion_limit
  1103. ):
  1104. iter_interval.append(
  1105. [middle + new_area_offset, right]
  1106. ) # 增加区间
  1107. expansion_depth -= 1
  1108. break # 这个区间迭代完成,跳出返回c
  1109. elif left_zero_c * right_zero_c == 0: # a或者b之间有一个是零点
  1110. if left_zero_c == 0: # a是零点
  1111. middle = left
  1112. if (
  1113. expansion_depth > 0
  1114. and abs((left + new_area_offset) - right)
  1115. > expansion_limit
  1116. ):
  1117. iter_interval.append([left + new_area_offset, right])
  1118. expansion_depth -= 1
  1119. break
  1120. else:
  1121. middle = right # 同上
  1122. if (
  1123. expansion_depth > 0
  1124. and abs(left - (right - new_area_offset))
  1125. > expansion_limit
  1126. ):
  1127. iter_interval.append([left, right - new_area_offset])
  1128. expansion_depth -= 1
  1129. break
  1130. elif left_zero_c * right_zero_c > 0: # q和p都有或都没用零点
  1131. if (
  1132. left_zero_c > 0
  1133. and abs(left - right) < zero_minimum_distance
  1134. ): # 如果ab足够小反围,则认为a和b之间不存在零点
  1135. if allow_extended_calculations:
  1136. # addNews('进入梯度运算')
  1137. middle = self.gradient_calculation(
  1138. y_value, left, right
  1139. )[1]
  1140. if middle is not None:
  1141. break
  1142. middle = None
  1143. break
  1144. iter_interval.append([right, middle]) # 其中一个方向继续迭代,另一个方向加入候选
  1145. right = middle
  1146. elif left_zero_c < 0: # 往一个方向收缩,同时另一个方向增加新的区间
  1147. if (
  1148. expansion_depth > 0
  1149. and abs(middle - right) > expansion_limit
  1150. ):
  1151. iter_interval.append([middle, right])
  1152. expansion_depth -= 1
  1153. right = middle
  1154. elif right_zero_c < 0: # 同上
  1155. if expansion_depth > 0 and abs(left - middle) > expansion_limit:
  1156. iter_interval.append([left, middle])
  1157. expansion_depth -= 1
  1158. left = middle
  1159. if abs(left - right) < accuracy: # a和b足够小,认为找到零点
  1160. middle = (left + right) / 2
  1161. middle_y = self(middle)
  1162. if (
  1163. secondary_verification
  1164. and abs(y_value - middle_y) > secondary_verification_effect
  1165. ):
  1166. middle = None
  1167. break
  1168. except BaseException as e:
  1169. logging.debug(str(e))
  1170. break
  1171. else: # 证明没有break
  1172. no_break = True
  1173. if middle is None:
  1174. continue # 去除c不存在的选项
  1175. if not no_break:
  1176. middle_list.append(middle)
  1177. else:
  1178. middle_list_deviation.append(middle)
  1179. answer = []
  1180. for i in middle_list:
  1181. self.memore_x.append(i)
  1182. self.memore_y.append(y_value)
  1183. answer.append(f"y={y_value} -> x={i}")
  1184. if return_all:
  1185. for i in middle_list_deviation:
  1186. answer.append(f"(误差)y={y_value} -> x={i}")
  1187. self.memory_answer += answer
  1188. return answer, middle_list
  1189. def calculation(self, x_in):
  1190. answer = []
  1191. for i in x_in:
  1192. try:
  1193. i = float(i)
  1194. y = self(i)
  1195. answer.append(f"x={i} -> y={y}={float(y)}")
  1196. if i not in self.memore_x:
  1197. self.memore_x.append(i)
  1198. self.memore_y.append(y)
  1199. except ValueError: # 捕捉运算错误
  1200. continue
  1201. self.best_value_core()
  1202. self.dataframe = pandas.DataFrame(
  1203. (self.x + self.memore_x, self.y + self.memore_y), index=("x", "y")
  1204. )
  1205. self.memory_answer += answer
  1206. return answer
  1207. def derivative(self, x_value, delta_x=0.1, must=False): # 可导函数求导,不可导函数逼近
  1208. derivatives = self.derivatives
  1209. try:
  1210. delta_x = abs(float(delta_x))
  1211. except (TypeError, ValueError):
  1212. delta_x = 0.1
  1213. try:
  1214. x_value = float(x_value)
  1215. if derivatives is not None and not must: # 导函数法
  1216. derivative_num = derivatives.evalf(subs={self.symbol_x: x_value})
  1217. derivative_method = "导函数求值"
  1218. else:
  1219. x1 = x_value - delta_x / 2
  1220. x2 = x_value + delta_x / 2
  1221. y1 = self(x1)
  1222. y2 = self(x2)
  1223. delta_x = y2 - y1
  1224. derivative_num = delta_x / delta_x
  1225. derivative_method = "逼近法求值"
  1226. except ValueError:
  1227. return None, None
  1228. answer = f"({derivative_method})x:{x_value} -> {derivative_num}"
  1229. return answer, derivative_num
  1230. @plugin_class_loading(get_path(r'template/funcsystem'))
  1231. class ExpProperty(ExpFuncInit, metaclass=ABCMeta):
  1232. def parity(self, precision=False): # 启动round处理
  1233. if not self.have_data_packet:
  1234. self.data_packet(float) # 运行Cul计算
  1235. if len(self.classification_x) != 1:
  1236. need_computing = True # 通过self计算y
  1237. else:
  1238. need_computing = False
  1239. y = self.y.copy()
  1240. x = self.x.copy()
  1241. a = self.start
  1242. b = self.end
  1243. a = -min([abs(a), abs(b)])
  1244. b = -a
  1245. flat = None # 0-偶函数,1-奇函数
  1246. for i in range(len(x)):
  1247. now_x = x[i] # 正项x
  1248. if now_x < a or now_x > b:
  1249. continue # x不在区间内
  1250. try:
  1251. if need_computing:
  1252. now_y = self(now_x)
  1253. else:
  1254. now_y = y[i] # 求得x的y
  1255. if need_computing:
  1256. symmetry_y = self(-now_x)
  1257. else:
  1258. symmetry_y = y[x.index(-now_x)] # 求得-x的y
  1259. if precision:
  1260. now_y = round(now_y, self.accuracy)
  1261. symmetry_y = round(symmetry_y, self.accuracy)
  1262. if symmetry_y == now_y == 0:
  1263. continue
  1264. elif symmetry_y == now_y:
  1265. if flat is None:
  1266. flat = 0
  1267. elif flat == 1:
  1268. assert False
  1269. elif symmetry_y == -now_y:
  1270. if flat is None:
  1271. flat = 1
  1272. elif flat == 0:
  1273. assert False
  1274. else:
  1275. assert False
  1276. except (AssertionError, ValueError, TypeError):
  1277. flat = None
  1278. break
  1279. return flat, [a, b]
  1280. def monotonic(self):
  1281. if not self.have_data_packet:
  1282. self.data_packet(float) # 运行Cul计算
  1283. classification_x = self.classification_x.copy()
  1284. increase_interval = [] # 增区间
  1285. minus_interval = [] # 减区间
  1286. interval = [] # 不增不减
  1287. for i in range(len(classification_x)):
  1288. x_list = classification_x[i]
  1289. y_list = classification_x[i]
  1290. last_x = None
  1291. last_y = None
  1292. start_x = None
  1293. flat = None # 当前研究反围:0-增区间,1-减区间,2-不增不减
  1294. for a in range(len(x_list)):
  1295. now_x = x_list[a] # 正项x
  1296. now_y = y_list[a] # 正项y
  1297. if start_x is None:
  1298. start_x = now_x
  1299. else:
  1300. if last_y > now_y: # 减区间
  1301. if flat is None or flat == 1: # 减区间
  1302. pass
  1303. elif flat == 0: # 增区间
  1304. increase_interval.append((start_x, last_x))
  1305. start_x = last_x
  1306. elif flat == 2:
  1307. interval.append((start_x, last_x))
  1308. start_x = last_x
  1309. flat = 1
  1310. elif last_y < now_y: # 增区间
  1311. if flat is None or flat == 0: # 增区间
  1312. pass
  1313. elif flat == 1: # 减区间
  1314. minus_interval.append((start_x, last_x))
  1315. start_x = last_x
  1316. elif flat == 2:
  1317. interval.append((start_x, last_x))
  1318. start_x = last_x
  1319. flat = 0
  1320. else: # 水平区间
  1321. if flat is None or flat == 2:
  1322. pass
  1323. elif flat == 1: # 减区间
  1324. minus_interval.append((start_x, last_x))
  1325. start_x = last_x
  1326. elif flat == 0: # 增区间
  1327. increase_interval.append((start_x, last_x))
  1328. start_x = last_x
  1329. flat = 2
  1330. last_x = now_x
  1331. last_y = now_y
  1332. if flat == 2:
  1333. interval.append((start_x, last_x))
  1334. elif flat == 1: # 减区间
  1335. minus_interval.append((start_x, last_x))
  1336. elif flat == 0: # 增区间
  1337. increase_interval.append((start_x, last_x))
  1338. return increase_interval, minus_interval, interval
  1339. def property_prediction(
  1340. self, output_prompt=lambda x: x, return_all=False, accuracy=None
  1341. ):
  1342. try:
  1343. accuracy = float(accuracy)
  1344. except ValueError:
  1345. accuracy = None
  1346. answer = []
  1347. parity = self.parity()
  1348. monotonic = self.monotonic()
  1349. periodic = self.periodic(output_prompt, accuracy)
  1350. symmetry_axis = self.symmetry_axis(output_prompt, accuracy)
  1351. symmetry_center = self.symmetry_center(output_prompt, accuracy)
  1352. if parity[0] == 1:
  1353. answer.append(f"奇函数 区间:[{parity[1][0]},{parity[1][0]}]")
  1354. elif parity[0] == 0:
  1355. answer.append(f"偶函数 区间:[{parity[1][0]},{parity[1][0]}]")
  1356. for i in monotonic[0]:
  1357. answer.append(f"增区间:[{i[0]},{i[1]}]")
  1358. for i in monotonic[1]:
  1359. answer.append(f"减区间:[{i[0]},{i[1]}]")
  1360. for i in monotonic[2]:
  1361. answer.append(f"水平区间:[{i[0]},{i[1]}]")
  1362. if self.derivatives:
  1363. answer.append(f"导函数:{self.derivatives}")
  1364. if periodic[0] is not None:
  1365. answer.append(f"最小正周期:{periodic[0]}")
  1366. if symmetry_axis[0] is not None:
  1367. answer.append(f"对称轴:x={symmetry_axis[0]}")
  1368. if symmetry_center[0] is not None:
  1369. answer.append(f"对称中心:{symmetry_center[0]}")
  1370. if return_all:
  1371. try:
  1372. for i in periodic[1][1:]:
  1373. answer.append(f"可能的最小正周期:{i}")
  1374. except BaseException as e:
  1375. logging.warning(str(e))
  1376. try:
  1377. for i in symmetry_axis[1][1:]:
  1378. answer.append(f"可能的对称轴:{i}")
  1379. except BaseException as e:
  1380. logging.warning(str(e))
  1381. try:
  1382. for i in symmetry_center[1][1:]:
  1383. answer.append(f"可能的对称中心:{i}")
  1384. except BaseException as e:
  1385. logging.warning(str(e))
  1386. return answer
  1387. def periodic(self, output_prompt=lambda x: x, accuracy=None): # 计算周期
  1388. if not tkinter.messagebox.askokcancel("提示", f"计算周期需要一定时间,是否执行?(计算过程程序可能无响应)"):
  1389. return None, [] # 无结果
  1390. if not self.have_data_packet:
  1391. self.data_packet(float)
  1392. possible_cycle_list = [] # 可能的周期
  1393. start = self.start
  1394. end = self.end
  1395. if accuracy is not None:
  1396. span = accuracy
  1397. else:
  1398. span = abs(start - end) / 20
  1399. output_prompt("正在预测可能的周期")
  1400. while start <= end:
  1401. try:
  1402. y = self(start)
  1403. x_list = self.dichotomy(y)[1]
  1404. output_prompt("迭代运算...")
  1405. # print(x_list)
  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 = self(start)
  1452. x_list = self.dichotomy(y)[1]
  1453. output_prompt("迭代运算...")
  1454. # print(x_list)
  1455. possible_symmetry_axis = []
  1456. for o_x in x_list:
  1457. a = (o_x + start) / 2
  1458. if a:
  1459. possible_symmetry_axis.append(round(a, self.accuracy))
  1460. possible_symmetry_axis_list.extend(list(set(possible_symmetry_axis)))
  1461. except BaseException as e:
  1462. logging.warning(str(e))
  1463. start += span
  1464. possible_symmetry_axis = [] # a的可能列表
  1465. c = 0
  1466. output_prompt("正在筛选结果")
  1467. for i in list(set(possible_symmetry_axis_list)):
  1468. n_c = possible_symmetry_axis_list.count(i)
  1469. if n_c > c:
  1470. possible_symmetry_axis = [i]
  1471. c = n_c
  1472. elif n_c == c:
  1473. possible_symmetry_axis.append(i)
  1474. try:
  1475. assert possible_symmetry_axis
  1476. possible_symmetry_axis.sort() #
  1477. output_prompt("计算完毕")
  1478. return possible_symmetry_axis[0], possible_symmetry_axis
  1479. except AssertionError:
  1480. output_prompt("无对称轴")
  1481. return None, [] # 无结果
  1482. def symmetry_center(self, output_prompt=lambda x: x, accuracy=None): # 计算对称中心
  1483. if not tkinter.messagebox.askokcancel("提示", f"计算对称中心需要一定时间,是否执行?(计算过程程序可能无响应)"):
  1484. return None, [] # 无结果
  1485. if not self.have_data_packet:
  1486. self.data_packet(float)
  1487. coordinate_points = [] # 可能的对称轴
  1488. start = self.start
  1489. end = self.end
  1490. output_prompt("正在计算坐标点")
  1491. if accuracy is not None:
  1492. span = accuracy
  1493. else:
  1494. span = 1
  1495. while start <= end:
  1496. try:
  1497. y = self(start)
  1498. x = start
  1499. coordinate_points.append((x, y))
  1500. except BaseException as e:
  1501. logging.warning(str(e))
  1502. start += span
  1503. possible_center_list = []
  1504. output_prompt("正在预测对称中心")
  1505. for i in coordinate_points:
  1506. for o in coordinate_points:
  1507. x = round((i[0] + o[0]) / 2, self.accuracy)
  1508. y = round((i[1] + o[1]) / 2, self.accuracy)
  1509. if i == o:
  1510. continue
  1511. possible_center_list.append((x, y))
  1512. possible_center = [] # a的可能列表
  1513. max_count = 0
  1514. output_prompt("正在筛选结果")
  1515. for i in list(set(possible_center_list)):
  1516. count = possible_center_list.count(i)
  1517. if count > max_count:
  1518. possible_center = [i]
  1519. max_count = count
  1520. elif count == max_count:
  1521. possible_center.append(i)
  1522. try:
  1523. assert not max_count < 5 or not possible_center
  1524. output_prompt("计算完毕")
  1525. possible_center.sort() #
  1526. return possible_center[int(len(possible_center) / 2)], possible_center
  1527. except AssertionError:
  1528. output_prompt("无对称中心")
  1529. return None, [] # 无结果
  1530. @plugin_class_loading(get_path(r'template/funcsystem'))
  1531. class ExpCheck(ExpFuncInit, metaclass=ABCMeta):
  1532. def check_monotonic(
  1533. self, parameters, output_prompt=lambda x: x, accuracy=None
  1534. ): # 检查单调性
  1535. result = True # 预测结果
  1536. try:
  1537. parameters = parameters.split(",")
  1538. start = float(parameters[0])
  1539. end = float(parameters[1])
  1540. flat = int(parameters[2]) # 当前研究反围:0-增区间,1-减区间,2-不增不减
  1541. except (IndexError, ValueError):
  1542. return False, ""
  1543. if start > end:
  1544. start, end = end, start
  1545. last_y = None
  1546. if accuracy is not None:
  1547. span = accuracy
  1548. else:
  1549. span = self.span
  1550. while start <= end:
  1551. try:
  1552. output_prompt("迭代运算...")
  1553. now_y = round(self(start), self.accuracy)
  1554. except (TypeError, ValueError):
  1555. start += span
  1556. continue
  1557. if last_y is None:
  1558. continue
  1559. if flat == 0 and last_y > now_y: # 增区间,o_y不小于y
  1560. result = False
  1561. break
  1562. elif flat == 1 and last_y < now_y: # 减小区间,o_y不小于y
  1563. result = False
  1564. break
  1565. elif flat == 2 and last_y != now_y:
  1566. result = False
  1567. break
  1568. last_y = now_y
  1569. start += span
  1570. monotonic_key = {0: "单调递增", 1: "单调递减", 2: "平行"}
  1571. result_key = {True: "成立", False: "不成立"}
  1572. return (
  1573. result,
  1574. f"{self}在[{parameters[0]},{parameters[1]}]{monotonic_key[flat]}{result_key[result]}",
  1575. )
  1576. def check_periodic(
  1577. self, parameters, output_prompt=lambda x: x, accuracy=None
  1578. ): # 检查周期性
  1579. result = True
  1580. try:
  1581. parameters = float(parameters)
  1582. except ValueError:
  1583. return False, ""
  1584. start = self.start
  1585. end = self.end
  1586. if accuracy is not None:
  1587. span = accuracy
  1588. else:
  1589. span = self.span
  1590. while start <= end:
  1591. try:
  1592. output_prompt("迭代运算...")
  1593. now_y = round(self(start), self.accuracy)
  1594. last_y = round(self(start + parameters), self.accuracy)
  1595. if now_y != last_y:
  1596. result = False
  1597. except BaseException as e:
  1598. logging.warning(str(e))
  1599. start += span
  1600. result_key = {True: "是", False: "不是"}
  1601. return result, f"{self}的周期{result_key[result]}{parameters}"
  1602. def check_symmetry_axis(
  1603. self, parameters, output_prompt=lambda x: x, accuracy=None
  1604. ): # 检查对称轴
  1605. result = True
  1606. try:
  1607. parameters = 2 * float(parameters)
  1608. except (ValueError, TypeError):
  1609. return False, ""
  1610. start = self.start
  1611. end = self.end
  1612. if accuracy is not None:
  1613. span = accuracy
  1614. else:
  1615. span = self.span
  1616. while start <= end:
  1617. try:
  1618. output_prompt("迭代运算...")
  1619. now_y = round(self(start), self.accuracy)
  1620. last_y = round(self(parameters - start), self.accuracy)
  1621. if now_y != last_y:
  1622. result = False
  1623. except BaseException as e:
  1624. logging.warning(str(e))
  1625. start += span
  1626. result_key = {True: "是", False: "不是"}
  1627. return result, f"{self}的对称轴{result_key[result]}{parameters}"
  1628. def check_symmetry_center(
  1629. self, parameters_input, output_prompt=lambda x: x, accuracy=None
  1630. ): # 检查对称中心
  1631. result = True
  1632. try:
  1633. parameters = []
  1634. for i in parameters_input.split(","):
  1635. parameters.append(float(i))
  1636. except ValueError:
  1637. return False, ""
  1638. start = self.start
  1639. end = self.end
  1640. if accuracy is not None:
  1641. span = accuracy
  1642. else:
  1643. span = self.span
  1644. while start <= end:
  1645. try:
  1646. output_prompt("迭代运算...")
  1647. now_y = round(self(start), self.accuracy)
  1648. last_y = round(self(2 * parameters[0] - start), self.accuracy)
  1649. if round((now_y + last_y) / 2, self.accuracy) != parameters[1]:
  1650. result = False
  1651. except BaseException as e:
  1652. logging.warning(str(e))
  1653. start += span
  1654. result_key = {True: "是", False: "不是"}
  1655. return result, f"{self}的对称中心{result_key[result]}{parameters}"
  1656. @plugin_class_loading(get_path(r'template/funcsystem'))
  1657. class ExpMemory(ExpFuncInit, metaclass=ABCMeta):
  1658. def hide_or_show(self): # 记忆数据显示和隐藏
  1659. if self.have_prediction:
  1660. if tkinter.messagebox.askokcancel("提示", f"是否显示{self}的记忆数据?"):
  1661. # addNews('记忆显示完毕')
  1662. self.have_prediction = False
  1663. else:
  1664. if tkinter.messagebox.askokcancel("提示", f"是否隐藏{self}的记忆数据?"):
  1665. # addNews('记忆隐藏完毕')
  1666. self.have_prediction = True
  1667. def clean_memory(self):
  1668. self.memore_x = []
  1669. self.memore_y = []
  1670. self.memory_answer = []
  1671. def get_memory(self):
  1672. if self.have_prediction:
  1673. return [], []
  1674. return self.memore_x, self.memore_y
  1675. @plugin_class_loading(get_path(r'template/funcsystem'))
  1676. class ExpFuncSon:
  1677. def __init__(
  1678. self, func, style, start=-10, end=10, span=0.1, accuracy=2, a_default=1
  1679. ):
  1680. self.symbol_x = sympy.Symbol("x")
  1681. named_domain = {
  1682. "a": a_default,
  1683. "x": self.symbol_x,
  1684. "Pi": sympy.pi,
  1685. "e": sympy.E,
  1686. "log": sympy.log,
  1687. "sin": sympy.sin,
  1688. "cos": sympy.cos,
  1689. "tan": sympy.tan,
  1690. "cot": lambda x: 1 / sympy.tan(x),
  1691. "csc": lambda x: 1 / sympy.sin(x),
  1692. "sec": lambda x: 1 / sympy.cos(x),
  1693. "sinh": sympy.sinh,
  1694. "cosh": sympy.cosh,
  1695. "tanh": sympy.tanh,
  1696. "asin": sympy.asin,
  1697. "acos": sympy.acos,
  1698. "atan": sympy.atan,
  1699. "abs": abs,
  1700. } # 这个是函数命名域
  1701. self.func = eval(func.replace(" ", ""), named_domain) # 函数解析式
  1702. self.func_str = func.replace(" ", "")
  1703. # 函数基本信息
  1704. self.func_name = f"y={func} a={a_default}" # 这个是函数名字
  1705. self.style = style # 绘制样式
  1706. # 数据辨析
  1707. try:
  1708. start = float(start)
  1709. end = float(end)
  1710. if start > end: # 使用float确保输入是数字,否则诱发ValueError
  1711. start, end = end, start
  1712. span = abs(float(span))
  1713. start = (start // span) * span # 确保start可以恰好被kd整除
  1714. end = (end // span + 1) * span
  1715. accuracy = abs(int(accuracy))
  1716. if accuracy >= 3:
  1717. accuracy = 3
  1718. except ValueError:
  1719. start, end, span, accuracy = -10, 10, 0.1, 2 # 保底设置
  1720. # 基本数据存储
  1721. self.accuracy = accuracy
  1722. self.start = start
  1723. self.end = end
  1724. self.span = span
  1725. # x和y数据存储
  1726. self.x = []
  1727. self.y = []
  1728. self.y_real = []
  1729. self.classification_x = [[]]
  1730. self.classification_y = [[]]
  1731. self.have_data_packet = False
  1732. def __call__(self, x):
  1733. return self.func.evalf(subs={self.symbol_x: x})
  1734. def __str__(self):
  1735. return f"{self.func_name} {self.start, self.end, self.span}"
  1736. def data_packet(self, number_type=float):
  1737. if self.have_data_packet:
  1738. return self.x, self.y, self.func_name, self.style
  1739. # 混合存储
  1740. self.y = []
  1741. self.y_real = []
  1742. self.x = []
  1743. self.classification_x = [[]]
  1744. self.classification_y = [[]]
  1745. classification_reason = [100]
  1746. last_y = None
  1747. last_monotonic = None # 单调性 0-增,1-减
  1748. now_monotonic = 1
  1749. try:
  1750. now_x = int(self.start)
  1751. while now_x <= int(self.end): # 因为range不接受小数
  1752. group_score = 0
  1753. balance = 1
  1754. try:
  1755. accuracy_x = round(now_x, self.accuracy)
  1756. now_y = number_type(self(accuracy_x)) # 数字处理方案
  1757. accuracy_y = round(now_y, self.accuracy)
  1758. if last_y is not None and last_y > now_y:
  1759. now_monotonic = 1
  1760. elif last_y is not None and last_y < now_y:
  1761. now_monotonic = 0
  1762. elif last_y is not None and last_y == now_y:
  1763. try:
  1764. middle_y = self(round(accuracy_x - 0.5 * self.span))
  1765. if middle_y == last_y == now_y: # 真实平衡
  1766. balance = 2
  1767. elif (
  1768. abs(middle_y - last_y) >= 10 * self.span
  1769. or abs(middle_y - now_y) >= 10 * self.span
  1770. ):
  1771. balance = 3
  1772. group_score += 5
  1773. except (ValueError, TypeError):
  1774. balance = 4
  1775. group_score += 9
  1776. now_monotonic = 2
  1777. if last_y is not None and last_monotonic != now_monotonic:
  1778. if (last_y * now_y) < 0:
  1779. group_score += 5
  1780. elif abs(last_y - now_y) >= (10 * self.span):
  1781. group_score += 5
  1782. if group_score >= 5 and (now_monotonic != 2 or balance != 2):
  1783. classification_reason.append(group_score)
  1784. self.classification_x.append([])
  1785. self.classification_y.append([])
  1786. last_monotonic = now_monotonic
  1787. self.x.append(accuracy_x) # 四舍五入减少计算量
  1788. self.y.append(now_y) # 不四舍五入
  1789. self.y_real.append(accuracy_y) # 四舍五入(用于求解最值)
  1790. self.classification_x[-1].append(accuracy_x)
  1791. self.classification_y[-1].append(now_y)
  1792. last_y = now_y
  1793. except (ValueError, TypeError):
  1794. classification_reason.append(0)
  1795. self.classification_x.append([])
  1796. self.classification_y.append([])
  1797. now_x += self.span
  1798. except (TypeError, IndexError, ValueError):
  1799. pass
  1800. new_classification_x = []
  1801. new_classification_y = []
  1802. classification_reason.append(99)
  1803. must_forward = False
  1804. for i in range(len(self.classification_x)): # 去除只有单个的组群
  1805. if len(self.classification_x[i]) <= 1 and not must_forward: # 检测到有单个群组
  1806. front_reason = classification_reason[i] # 前原因
  1807. back_reason = classification_reason[i + 1] # 后原因
  1808. if front_reason < back_reason: # 前原因小于后原因,连接到前面
  1809. try:
  1810. new_classification_x[-1] += self.classification_x[i]
  1811. new_classification_y[-1] += self.classification_y[i]
  1812. except IndexError: # 按道理不应该出现这个情况
  1813. new_classification_x.append(self.classification_x[i])
  1814. new_classification_y.append(self.classification_y[i])
  1815. else:
  1816. new_classification_x.append(self.classification_x[i])
  1817. new_classification_y.append(self.classification_y[i])
  1818. must_forward = True
  1819. else:
  1820. if not must_forward:
  1821. new_classification_x.append(self.classification_x[i])
  1822. new_classification_y.append(self.classification_y[i])
  1823. else:
  1824. new_classification_x[-1] += self.classification_x[i]
  1825. new_classification_y[-1] += self.classification_y[i]
  1826. must_forward = False
  1827. self.classification_x = new_classification_x
  1828. self.classification_y = new_classification_y
  1829. self.have_data_packet = True
  1830. return self.x, self.y, self.func_name, self.style
  1831. def get_plot_data(self):
  1832. if not self.have_data_packet:
  1833. self.data_packet()
  1834. return (
  1835. self.classification_x,
  1836. self.classification_y,
  1837. self.func_name,
  1838. self.style,
  1839. )