@@ -509,6 +509,21 @@ function varmap_get(varmap, var, default = nothing)
509
509
return default
510
510
end
511
511
512
+ """
513
+ $(TYPEDSIGNATURES)
514
+
515
+ Check if `varmap::Dict{Any, Any}` contains cyclic values for any symbolic variables in
516
+ `syms`. Falls back on the basis of `symbolic_container(indp)`. Returns `false` by default.
517
+ """
518
+ function detect_cycles (indp, varmap, syms)
519
+ if hasmethod (symbolic_container, Tuple{typeof (indp)}) &&
520
+ (sc = symbolic_container (indp)) != indp
521
+ return detect_cycles (sc, varmap, syms)
522
+ else
523
+ return false
524
+ end
525
+ end
526
+
512
527
anydict (d:: Dict{Any, Any} ) = d
513
528
anydict (d) = Dict {Any, Any} (d)
514
529
anydict () = Dict {Any, Any} ()
@@ -560,14 +575,24 @@ function _updated_u0_p_internal(
560
575
end
561
576
562
577
function fill_u0 (prob, u0; defs = nothing , use_defaults = false )
563
- vsyms = variable_symbols (prob)
564
- idx_to_vsym = anydict (variable_index (prob, sym) => sym for sym in vsyms)
578
+ fill_vars (prob, u0; defs, use_defaults, allsyms = variable_symbols (prob),
579
+ index_function = variable_index)
580
+ end
581
+
582
+ function fill_p (prob, p; defs = nothing , use_defaults = false )
583
+ fill_vars (prob, p; defs, use_defaults, allsyms = parameter_symbols (prob),
584
+ index_function = parameter_index)
585
+ end
586
+
587
+ function fill_vars (
588
+ prob, varmap; defs = nothing , use_defaults = false , allsyms, index_function)
589
+ idx_to_vsym = anydict (index_function (prob, sym) => sym for sym in allsyms)
565
590
sym_to_idx = anydict ()
566
591
idx_to_sym = anydict ()
567
592
idx_to_val = anydict ()
568
- for (k, v) in u0
593
+ for (k, v) in varmap
569
594
v === nothing && continue
570
- idx = variable_index (prob, k)
595
+ idx = index_function (prob, k)
571
596
idx === nothing && continue
572
597
if ! (idx isa AbstractArray) || symbolic_type (k) != ArraySymbolic ()
573
598
idx = (idx,)
@@ -582,9 +607,9 @@ function fill_u0(prob, u0; defs = nothing, use_defaults = false)
582
607
idx_to_val[ii] = vv
583
608
end
584
609
end
585
- for sym in vsyms
610
+ for sym in allsyms
586
611
haskey (sym_to_idx, sym) && continue
587
- idx = variable_index (prob, sym)
612
+ idx = index_function (prob, sym)
588
613
haskey (idx_to_val, idx) && continue
589
614
sym_to_idx[sym] = idx
590
615
idx_to_sym[idx] = sym
@@ -600,65 +625,33 @@ function fill_u0(prob, u0; defs = nothing, use_defaults = false)
600
625
for (idx, val) in idx_to_val
601
626
newvals[idx_to_sym[idx]] = val
602
627
end
603
- for (k, v) in u0
628
+ for (k, v) in varmap
604
629
haskey (sym_to_idx, k) && continue
605
630
newvals[k] = v
606
631
end
607
632
return newvals
608
633
end
609
634
610
- function fill_p (prob, p; defs = nothing , use_defaults = false )
611
- psyms = parameter_symbols (prob)
612
- idx_to_psym = anydict (parameter_index (prob, sym) => sym for sym in psyms)
613
- sym_to_idx = anydict ()
614
- idx_to_sym = anydict ()
615
- idx_to_val = anydict ()
616
- for (k, v) in p
617
- v === nothing && continue
618
- idx = parameter_index (prob, k)
619
- idx === nothing && continue
620
- if ! (idx isa AbstractArray) || symbolic_type (k) != ArraySymbolic ()
621
- idx = (idx,)
622
- k = (k,)
623
- v = (v,)
624
- end
625
- for (kk, vv, ii) in zip (k, v, idx)
626
- sym_to_idx[kk] = ii
627
- kk = idx_to_psym[ii]
628
- sym_to_idx[kk] = ii
629
- idx_to_sym[ii] = kk
630
- idx_to_val[ii] = vv
631
- end
632
- end
633
- for sym in psyms
634
- haskey (sym_to_idx, sym) && continue
635
- idx = parameter_index (prob, sym)
636
- haskey (idx_to_val, idx) && continue
637
- sym_to_idx[sym] = idx
638
- idx_to_sym[idx] = sym
639
- idx_to_val[idx] = if defs != = nothing &&
640
- (defval = varmap_get (defs, sym)) != = nothing &&
641
- (symbolic_type (defval) != NotSymbolic () || use_defaults)
642
- defval
643
- else
644
- getp (prob, sym)(prob)
645
- end
646
- end
647
- newvals = anydict ()
648
- for (idx, val) in idx_to_val
649
- newvals[idx_to_sym[idx]] = val
650
- end
651
- for (k, v) in p
652
- haskey (sym_to_idx, k) && continue
653
- newvals[k] = v
635
+ struct CyclicDependencyError <: Exception
636
+ varmap:: Dict{Any, Any}
637
+ vars:: Any
638
+ end
639
+
640
+ function Base. showerror (io:: IO , err:: CyclicDependencyError )
641
+ println (io, " Detected cyclic dependency in initial values:" )
642
+ for (k, v) in err. varmap
643
+ println (io, k, " => " , " v" )
654
644
end
655
- return newvals
645
+ println (io, " While trying to solve for variables: " , err . vars)
656
646
end
657
647
658
648
function _updated_u0_p_symmap (prob, u0, :: Val{true} , p, :: Val{false} , t0)
659
649
isdep = any (symbolic_type (v) != = NotSymbolic () for (_, v) in u0)
660
650
isdep || return remake_buffer (prob, state_values (prob), keys (u0), values (u0)), p
661
651
652
+ if detect_cycles (prob, u0, variable_symbols (prob))
653
+ throw (CyclicDependencyError (u0, variable_symbols (prob)))
654
+ end
662
655
for (k, v) in u0
663
656
u0[k] = symbolic_type (v) === NotSymbolic () ? v : symbolic_evaluate (v, u0)
664
657
end
@@ -680,6 +673,9 @@ function _updated_u0_p_symmap(prob, u0, ::Val{false}, p, ::Val{true}, t0)
680
673
isdep = any (symbolic_type (v) != = NotSymbolic () for (_, v) in p)
681
674
isdep || return u0, remake_buffer (prob, parameter_values (prob), keys (p), values (p))
682
675
676
+ if detect_cycles (prob, p, parameter_symbols (prob))
677
+ throw (CyclicDependencyError (p, parameter_symbols (prob)))
678
+ end
683
679
for (k, v) in p
684
680
p[k] = symbolic_type (v) === NotSymbolic () ? v : symbolic_evaluate (v, p)
685
681
end
@@ -707,6 +703,10 @@ function _updated_u0_p_symmap(prob, u0, ::Val{true}, p, ::Val{true}, t0)
707
703
end
708
704
709
705
varmap = merge (u0, p)
706
+ allsyms = [variable_symbols (prob); parameter_symbols (prob)]
707
+ if detect_cycles (prob, varmap, allsyms)
708
+ throw (CyclicDependencyError (varmap, allsyms))
709
+ end
710
710
if is_time_dependent (prob)
711
711
varmap[only (independent_variable_symbols (prob))] = t0
712
712
end
0 commit comments