@@ -50,6 +50,13 @@ export function buildLatexDocument(
5050 parts . push ( buildLatexAlign ( model . expressions ) ) ;
5151 }
5252
53+ const loopInfo = extractLoopInfo ( model ) ;
54+ if ( loopInfo && loopInfo . updates . length > 0 ) {
55+ parts . push ( '\\subsection{Cyclic Update}' ) ;
56+ const lines = loopInfo . updates . map ( ( u ) => ` ${ renderLoopUpdateLine ( u ) } ` ) ;
57+ parts . push ( `Before each cycle:\n\\begin{align}\n${ lines . join ( ' \\\\\n' ) } \n\\end{align}` ) ;
58+ }
59+
5360 if ( opts . includeInits && model . inits . length > 0 ) {
5461 parts . push ( `\\subsection{${ initsTitle ( model ) } }` ) ;
5562 parts . push ( buildLatexTable ( model . inits ) ) ;
@@ -104,6 +111,13 @@ export function buildMarkdownDocument(
104111 parts . push ( buildMarkdownAlign ( model . expressions ) ) ;
105112 }
106113
114+ const loopInfo = extractLoopInfo ( model ) ;
115+ if ( loopInfo && loopInfo . updates . length > 0 ) {
116+ parts . push ( '### Cyclic Update' ) ;
117+ const lines = loopInfo . updates . map ( ( u ) => ` ${ renderLoopUpdateLine ( u ) } ` ) ;
118+ parts . push ( `Before each cycle:\n\n$$\n\\begin{aligned}\n${ lines . join ( ' \\\\\n' ) } \n\\end{aligned}\n$$` ) ;
119+ }
120+
107121 if ( opts . includeInits && model . inits . length > 0 ) {
108122 parts . push ( `### ${ initsTitle ( model ) } ` ) ;
109123 parts . push ( buildMarkdownTable ( model . inits ) ) ;
@@ -133,7 +147,26 @@ function buildArgRangeLatex(model: ParsedModel): string {
133147 const start = model . argument . entries [ 0 ] . value ;
134148 const finish = model . argument . entries [ 1 ] . value ;
135149 const step = model . argument . entries [ 2 ] . value ;
136- return `${ arg } \\in \\left[${ start } ,\\, ${ finish } \\right], \\quad \\Delta ${ arg } = ${ step } ` ;
150+
151+ const loopInfo = extractLoopInfo ( model ) ;
152+ let effectiveFinish = finish ;
153+ if ( loopInfo ) {
154+ const s = parseFloat ( start ) ;
155+ const f = parseFloat ( finish ) ;
156+ const n = parseFloat ( loopInfo . count ) ;
157+ if ( ! isNaN ( s ) && ! isNaN ( f ) && ! isNaN ( n ) )
158+ effectiveFinish = String ( s + n * ( f - s ) ) ;
159+ else
160+ effectiveFinish = `${ start } + ${ loopInfo . count } \\cdot (${ finish } - ${ start } )` ;
161+ }
162+
163+ let result = `${ arg } \\in \\left[${ start } ,\\, ${ effectiveFinish } \\right], \\quad \\Delta ${ arg } = ${ step } ` ;
164+ if ( loopInfo ) {
165+ const duration = ( ! isNaN ( parseFloat ( start ) ) && ! isNaN ( parseFloat ( finish ) ) ) ?
166+ String ( parseFloat ( finish ) - parseFloat ( start ) ) : `${ finish } - ${ start } ` ;
167+ result += `, \\quad ${ arg } _{\\text{cycle}} = ${ duration } ` ;
168+ }
169+ return result ;
137170}
138171
139172function buildLatexArgRange ( model : ParsedModel ) : string {
@@ -208,6 +241,32 @@ function compactExprItems(model: ParsedModel): string[] {
208241 } ) ;
209242}
210243
244+ interface LoopUpdate { variable : string ; value : string }
245+
246+ interface LoopInfo { count : string ; updates : LoopUpdate [ ] }
247+
248+ function extractLoopInfo ( model : ParsedModel ) : LoopInfo | undefined {
249+ if ( model . loops . length === 0 ) return undefined ;
250+ const loop = model . loops [ 0 ] ;
251+ let count = '' ;
252+ const updates : LoopUpdate [ ] = [ ] ;
253+ for ( const entry of loop . entries ) {
254+ if ( entry . name === 'count' )
255+ count = entry . value ;
256+ else {
257+ const variable = entry . name . replace ( / \s * \+ $ / , '' ) ;
258+ updates . push ( { variable, value : entry . value } ) ;
259+ }
260+ }
261+ return count ? { count, updates} : undefined ;
262+ }
263+
264+ function renderLoopUpdateLine ( u : LoopUpdate ) : string {
265+ const varLatex = identifierToLatex ( u . variable ) ;
266+ const valLatex = expressionToLatex ( u . value ) ;
267+ return `${ varLatex } \\leftarrow ${ varLatex } + ${ valLatex } ` ;
268+ }
269+
211270function buildLatexCompact ( model : ParsedModel , opts : ConvertOptions ) : string {
212271 const parts : string [ ] = [ ] ;
213272
@@ -231,11 +290,17 @@ function buildLatexCompact(model: ParsedModel, opts: ConvertOptions): string {
231290 parts . push ( `where\n${ lines . join ( '\n' ) } ` ) ;
232291 }
233292
293+ const loopInfo = extractLoopInfo ( model ) ;
294+ if ( loopInfo && loopInfo . updates . length > 0 ) {
295+ const lines = loopInfo . updates . map ( ( u ) => `\\[ ${ renderLoopUpdateLine ( u ) } \\]` ) ;
296+ parts . push ( `before each cycle:\n${ lines . join ( '\n' ) } ` ) ;
297+ }
298+
234299 if ( opts . includeParameters && model . parameters . length > 0 )
235- parts . push ( `${ plural ( 'Parameter' , model . parameters . length ) } :\n\n ${ buildLatexTable ( model . parameters ) } ` ) ;
300+ parts . push ( `${ plural ( 'Parameter' , model . parameters . length ) } :\n${ buildLatexList ( model . parameters ) } ` ) ;
236301
237302 if ( opts . includeConstants && model . constants . length > 0 )
238- parts . push ( `${ plural ( 'Constant' , model . constants . length ) } :\n\n ${ buildLatexTable ( model . constants ) } ` ) ;
303+ parts . push ( `${ plural ( 'Constant' , model . constants . length ) } :\n${ buildLatexList ( model . constants ) } ` ) ;
239304
240305 return parts . join ( '\n\n' ) ;
241306}
@@ -263,15 +328,40 @@ function buildMarkdownCompact(model: ParsedModel, opts: ConvertOptions): string
263328 parts . push ( `where\n${ lines . join ( '\n' ) } ` ) ;
264329 }
265330
331+ const loopInfo = extractLoopInfo ( model ) ;
332+ if ( loopInfo && loopInfo . updates . length > 0 ) {
333+ const lines = loopInfo . updates . map ( ( u ) => `$$${ renderLoopUpdateLine ( u ) } $$` ) ;
334+ parts . push ( `before each cycle:\n${ lines . join ( '\n' ) } ` ) ;
335+ }
336+
266337 if ( opts . includeParameters && model . parameters . length > 0 )
267- parts . push ( `${ plural ( 'Parameter' , model . parameters . length ) } :\n\n ${ buildMarkdownTable ( model . parameters ) } ` ) ;
338+ parts . push ( `${ plural ( 'Parameter' , model . parameters . length ) } :\n${ buildMarkdownList ( model . parameters ) } ` ) ;
268339
269340 if ( opts . includeConstants && model . constants . length > 0 )
270- parts . push ( `${ plural ( 'Constant' , model . constants . length ) } :\n\n ${ buildMarkdownTable ( model . constants ) } ` ) ;
341+ parts . push ( `${ plural ( 'Constant' , model . constants . length ) } :\n${ buildMarkdownList ( model . constants ) } ` ) ;
271342
272343 return parts . join ( '\n\n' ) ;
273344}
274345
346+ function buildLatexList ( entries : AnnotatedLine [ ] ) : string {
347+ const items = entries . map ( ( e ) => {
348+ const name = `$${ identifierToLatex ( e . name ) } $` ;
349+ const value = `$${ e . value } $` ;
350+ const units = e . units ? ` (${ e . units } )` : '' ;
351+ return ` \\item ${ name } = ${ value } ${ units } ` ;
352+ } ) . join ( '\n' ) ;
353+ return `\\begin{itemize}\n${ items } \n\\end{itemize}` ;
354+ }
355+
356+ function buildMarkdownList ( entries : AnnotatedLine [ ] ) : string {
357+ return entries . map ( ( e ) => {
358+ const name = `$${ identifierToLatex ( e . name ) } $` ;
359+ const value = `$${ e . value } $` ;
360+ const units = e . units ? ` (${ e . units } )` : '' ;
361+ return `- ${ name } = ${ value } ${ units } ` ;
362+ } ) . join ( '\n' ) ;
363+ }
364+
275365function buildLatexTable ( entries : AnnotatedLine [ ] ) : string {
276366 const hasUnits = entries . some ( ( e ) => e . units ) ;
277367 const cols = hasUnits ? 'lll' : 'll' ;
0 commit comments