chiark / gitweb /
curveopt: fix handling of empty lines from findcurve
[moebius3.git] / symbolic.py
index f12a96d18d9496645394195604ef286abb1d7f61..8680378ea06d906cbf58b4d230f09451e5ec281d 100644 (file)
@@ -9,6 +9,10 @@ import numpy as np
 
 from moedebug import *
 
+# When cse() is called for something containing BaseVector, it
+# produces infinite recursion.
+#def cse(x, *a, **kw): return ((), (x,))
+
 def dprint(*args):
   if not dbg_enabled(): return
   print(*args)
@@ -21,6 +25,8 @@ def dbg(*args):
     print('\n          =\n')
     pprint(cse(eval(vn)))
 
+def sqnorm(v): return v & v
+
 N = CoordSysCartesian('N')
 
 calculated = False
@@ -38,47 +44,105 @@ A, B, C, D = vector_symbols('A B C D')
 p = vector_symbols('p')
 
 E, H = vector_symbols('E H')
+F0, G0 = vector_symbols('F0 G0')
 En, Hn = vector_symbols('En Hn')
 
-EFl, GHl = symbols('EFl GHl')
+EFlq, HGlq = symbols('EFlq HGlq')
 
 def vector_component(v, ix):
   return v.components[N.base_vectors()[ix]]
 
 # x array in numerical algorithm has:
 #    N x 3    coordinates of points 0..N-3
-#    1        EFl = length parameter |EF| for point 1
-#    1        GHl = length parameter |GH| for point N-2
+#    1        EFlq = sqrt of length parameter |EF| for point 1
+#    1        HGlq = sqrt of length parameter |HG| for point N-2
 
 # fixed array in numerical algorithm has:
 #    4 x 3    E, En, H, Hn
 
 #def subst_vect():
 
+iterations = []
+
+class SomeIteration():
+  def __init__(ar, names, size, expr):
+    ar.names_string = names
+    ar.names = names.split(' ')
+    ar.name = ar.names[0]
+    ar.size = size
+    ar.expr = expr
+    if dbg_enabled():
+      print('\n   ' + ar.name + '\n')
+      print(expr)
+    iterations.append(ar)
+
+  def gen_calculate_cost(ar):
+    ar._gen_array()
+    cprint('for (P=0; P<(%s); P++) {' % ar.size)
+    ar._cassign()
+    cprint('}')
+
+class ScalarArray(SomeIteration):
+  def _gen_array(ar):
+    cprint('double A_%s[%s];' % (ar.name, ar.size))
+  def gen_references(ar):
+    for ai in range(0, len(ar.names)):
+      ar._gen_reference(ai, ar.names[ai])
+  def _gen_reference(ar, ai, an):
+    cprintraw('#define %s A_%s[P%+d]' % (an, ar.name, ai))
+  def _cassign(ar):
+    cassign(ar.expr, ar.name, 'tmp_'+ar.name)
+  def s(ar):
+    return symbols(ar.names_string)
+
+class CoordArray(ScalarArray):
+  def _gen_array(ar):
+    cprint('double A_%s[%s][3];' % (ar.name, ar.size))
+  def _gen_reference(ar, ai, an):
+    ScalarArray._gen_reference(ar, ai, an)
+    gen_point_coords_macro(an)
+  def _cassign(ar):
+    cassign_vector(ar.expr, ar.name, 'tmp_'+ar.name)
+  def s(ar):
+    return vector_symbols(ar.names_string)
+
+class CostComponent(SomeIteration):
+  def __init__(cc, size, expr):
+    cc.size = size
+    cc.expr = expr
+    iterations.append(cc)
+  def gen_references(cc): pass
+  def _gen_array(cc): pass
+  def _cassign(cc):
+    cassign(cc.expr, 'P_cost', 'tmp_cost')
+    cprint('cost += P_cost;')
+
 def calculate():
   global calculated
   if calculated: return
 
-  Q = B + 0.5 * (B - A)
-  R = C + 0.5 * (C - D)
-  QR = R - Q
-  BC = C - B
-  cost_ABCD = (QR & QR) / (BC & BC)
-  global cost_ABCD
-  dbg('cost_ABCD')
-  dprint(A)
+  # ---------- actual cost computation formulae ----------
+
+  global F, G
+  F = E + En * pow(EFlq, 2)
+  G = H + Hn * pow(HGlq, 2)
+
+  global a,b, al,bl, au,bu
+  a,  b  = CoordArray ('a_ b_',   'NP-1', B-A           ).s() # [mm]
+  al, bl = ScalarArray('al bl',   'NP-1', a.magnitude() ).s() # [mm]
+  au, bu = CoordArray ('au bu',   'NP-1', a / al        ).s() # [1]
+
+  tan_theta = (au ^ bu) / (au & bu)     # [1]     bending
 
-  F = E + En * EFl
-  G = H + Hn * GHl
+  global mu, nu
+  mu, nu = CoordArray ('mu nu', 'NP-2', tan_theta ).s() # [1]
 
-  #cost_EFCD = subst_vect(cost_ABCD, (A,E), (B,F))
-  #cost_FBCD = subst_vect(cost_ABCD,        (A,F))
-  #cost_ABCG = subst_vect(cost_ABCD,        (D,G))
-  #cost_ABGH = subst_vect(cost_ABCD, (C,G), (D,H))
+  CostComponent('NP-3', sqnorm(mu - nu)) # [1]
 
-  # diff_A_i = cost_ABCD.diff(vector_component(A, 0))
-  # global diff_A_i
-  # dbg('diff_A_i')
+  dl2 = pow(al - bl, 2) # [mm^2]
+  CostComponent('NP-2', dl2 / (al*bl)) # [1]
+
+  # ---------- end of cost computation formulae ----------
 
   calculated = True
 
@@ -105,6 +169,12 @@ def cassign(v, assign_to, tmp_prefix):
   v = cse_prep_cprint(v, tmp_prefix)
   cprint(ourccode(v, assign_to=assign_to))
 
+def cassign_vector(v, assign_to, tmp_prefix):
+  ijk = 'i j k'.split(' ')
+  for ii in range(0, len(ijk)):
+    x = v & getattr(N, ijk[ii])
+    cassign(x, '%s[%d]' % (assign_to, ii), '%s_%s' % (tmp_prefix, ijk[ii]))
+
 def gen_diff(current, smalls):
   global j
   if not smalls:
@@ -137,45 +207,84 @@ def gen_diff(current, smalls):
 def gen_misc():
   cprintraw('// AUTOGENERATED - DO NOT EDIT\n')
 
-def gen_point_index_macro(macro_basename, c_array_name, base_index):
-  cprintraw('#define %s (&%s[%s])'
-            % (macro_basename, c_array_name, base_index))
+def gen_point_coords_macro(macro_basename):
   ijk = 'i j k'.split(' ')
   for ii in range(0, len(ijk)):
     cprintraw('#define %s_%s (%s[%d])'
               % (macro_basename, ijk[ii], macro_basename, ii))
 
-def gen_abcd_ijk_macros():
+def gen_point_index_macro(macro_basename, c_array_name, base_index):
+  cprintraw('#define %s (&%s[%s])'
+            % (macro_basename, c_array_name, base_index))
+  gen_point_coords_macro(macro_basename)
+
+def gen_point_references():
   abcd = 'A B C D'.split(' ')
-  eh = 'E En H Hn'.split(' ')
-  for ehi in range(0, len(eh)):
-    gen_point_index_macro(eh[ehi], 'FIXED', ehi * 3)
+
+  gen_point_index_macro('E',  'INPUT', '3*0')
+  gen_point_index_macro('F0', 'INPUT', '3*1')
+  gen_point_index_macro('G0', 'INPUT', '3*(NP-2)')
+  gen_point_index_macro('H',  'INPUT', '3*(NP-1)')
+  cprintraw(         '#define NINPUT  ( 3*(NP-0) )')
+
+  gen_point_index_macro('En', 'PREP', '3*0')
+  gen_point_index_macro('Hn', 'PREP', '3*1')
+  cprintraw(         '#define NPREP   (3*2)')
+
+  cprintraw('#define NX_DIRECT 3*(NP-4)')
+  cprint('#define POINT(PP) (')
+  cprint(' (PP) == 0    ? E :')
+  cprint(' (PP) == 1    ? F :')
+  cprint(' (PP) == NP-2 ? G :')
+  cprint(' (PP) == NP-1 ? H :')
+  cprint(' &X[3*((PP)-2)]')
+  cprintraw(')')
+
+  cprintraw('#define EFlq X[ NX_DIRECT + 0 ]')
+  cprintraw('#define HGlq X[ NX_DIRECT + 1 ]')
+  cprintraw('#define NX    ( NX_DIRECT + 2 )')
 
   for ai in range(0, len(abcd)):
-    gen_point_index_macro(abcd[ai], 'X', '(P%+d) * 3' % (ai - 2))
+    cprintraw('#define %s POINT(P%+d)' % (abcd[ai], ai))
+    gen_point_coords_macro(abcd[ai])
 
-  cprint('#define E_CALCULATE_MID')
-  cassign(cost_ABCD,'d','dtmp_mid')
+  for si in iterations:
+    si.gen_references()
 
-def gen_e_calculate():
-  cprint('#define E_CALCULATE_MID')
-  cprint('if (P==0) '
-  cassign(cost_ABCD,'d','dtmp_mid')
+  cprintraw('')
+
+def gen_prepare():
+  cprint('#define PREPARE')
+  cprint('memcpy(X, &INPUT[3*2], sizeof(double) * NX_DIRECT);')
+  for EH,EHs,FG0,FGs in ((E,'E', F0,'F'),
+                         (H,'H', G0,'G')):
+    EFHGv = FG0 - EH
+    EFHGl = EFHGv.magnitude()
+    EFHGlq = sqrt(EFHGl)
+    cassign_vector(EFHGv/EFHGl, EHs+'n', 'tmp_'+EHs)
+    cassign(EFHGlq, EHs+FGs+'lq', 'tmp_l'+EHs)
+  cprintraw('')
 
-def gen_f_populate():
-  cprint('#define F_POPULATE')
-  cassign(cost_ABCD,'F','ftmp')
+def gen_calculate_FG():
+  cprintraw('#define DECLARE_F_G double F[3], G[3];')
+  cprint('#define CALCULATE_F_G')
+  cassign_vector(F,'F','tmp_F')
+  cassign_vector(G,'G','tmp_G')
   cprintraw('')
 
-def gen_j_populate():
-  cprint('#define J_POPULATE')
-  gen_diff(result_dirnscaled, (sh*sh*la, th*th*la))
+def gen_calculate_cost():
+  cprint('#define CALCULATE_COST')
+  cprint('double cost=0, P_cost;')
+  for si in iterations:
+    si.gen_calculate_cost()
   cprintraw('')
 
 def gen_C():
   gen_misc()
-  gen_abcd_ijk_macros()
-  gen_e_calculate()
+  gen_point_references()
+  gen_prepare()
+  gen_calculate_FG()
+  gen_calculate_cost()
 
 def get_python():
   # https://github.com/sympy/sympy/issues/13642