2024-07-23 19:21:53 +00:00
// RogueViz -- SAG embedder: main file
// Copyright (C) 2011-24 Zeno Rogue, see 'hyper.cpp' for details
2020-03-29 11:41:56 +00:00
2024-07-23 19:21:53 +00:00
# include "sag.h"
# include "cells.cpp"
# include "data.cpp"
# include "functions.cpp"
# include "annealing.cpp"
2022-08-23 19:48:54 +00:00
2020-03-29 11:41:56 +00:00
namespace rogueviz {
namespace sag {
2024-07-23 19:21:53 +00:00
flagtype state ;
2020-03-29 11:41:56 +00:00
2024-07-23 19:21:53 +00:00
// std::mt19937 los;
2022-08-20 14:43:26 +00:00
2024-07-23 19:21:53 +00:00
bool auto_repeat ;
extern void output_stats ( ) ;
2022-08-20 14:43:26 +00:00
2024-07-23 19:21:53 +00:00
int sag_ittime = 100 ;
int ipturn = 100 ;
bool auto_visualize = true ;
2022-10-23 13:49:16 +00:00
2024-07-23 19:21:53 +00:00
void iterate ( ) {
if ( ! sagmode ) return ;
int t1 = SDL_GetTicks ( ) ;
# if CAP_SDL && !CAP_SDL2
int last = - 1 ;
# endif
for ( int i = 0 ; i < ipturn ; i + + ) {
numiter + + ;
sag : : saiter ( ) ;
# if CAP_SDL && !CAP_SDL2
int q = i * sag_ittime / ipturn ;
if ( q > last ) { last = 1 ; SDL_PumpEvents ( ) ; }
# endif
2022-08-20 14:43:26 +00:00
}
2024-07-23 19:21:53 +00:00
int t2 = SDL_GetTicks ( ) ;
int t = t2 - t1 ;
if ( t < ( sag_ittime + 1 ) / 2 ) ipturn * = 2 ;
else if ( t > sag_ittime * 2 ) ipturn / = 2 ;
else ipturn = ipturn * sag_ittime / t ;
print ( hlog , format ( " it %12Ld temp %6.4f [2:%8.6f,10:%8.6f,50:%8.6f] cost = %f \n " ,
numiter , double ( sag : : temperature ) ,
( double ) exp ( - 2 * exp ( - sag : : temperature ) ) ,
( double ) exp ( - 10 * exp ( - sag : : temperature ) ) ,
( double ) exp ( - 50 * exp ( - sag : : temperature ) ) ,
( double ) sag : : cost ) ) ;
if ( auto_visualize ) create_viz ( ) ;
}
2021-06-25 11:49:55 +00:00
2024-07-23 19:21:53 +00:00
bool turn ( int delta ) {
if ( vizsa_start ) {
if ( vizsa_start = = - 1 ) vizsa_start = ticks ;
auto t = ticks ;
double d = ( t - vizsa_start ) / ( 1000. * vizsa_len ) ;
if ( d > 1 & & auto_repeat ) {
optimize_sag_loglik_auto ( ) ;
output_stats ( ) ;
vizsa_start = - 1 ;
2021-06-25 11:49:55 +00:00
}
2024-07-23 19:21:53 +00:00
if ( d > 1 ) sagmode = sagOff ;
2020-03-29 11:41:56 +00:00
else {
temperature = hightemp - ( d * ( hightemp - lowtemp ) ) ;
2024-07-23 19:21:53 +00:00
sagmode = sagSA ;
2022-08-26 10:43:59 +00:00
}
}
2024-07-23 19:21:53 +00:00
iterate ( ) ;
2022-08-20 14:43:26 +00:00
2024-07-23 19:21:53 +00:00
return false ;
// shmup::pc[0]->rebase();
}
2022-08-23 19:48:54 +00:00
2024-07-23 19:21:53 +00:00
void set_inverse ( ) {
if ( method = = smMatch ) vizflags | = RV_INVERSE_WEIGHT ;
else vizflags & = ~ RV_INVERSE_WEIGHT ;
}
2022-08-23 19:48:54 +00:00
2024-07-23 19:21:53 +00:00
void menu ( ) {
cmode | = sm : : MAYDARK | sm : : SIDE ;
gamescreen ( ) ;
dialog : : init ( " SAG settings " ) ;
2022-10-23 13:49:59 +00:00
2024-07-23 19:21:53 +00:00
dialog : : addSelItem ( XLAT ( " temperature " ) , fts ( sag : : temperature ) , ' t ' ) ;
dialog : : add_action ( [ ] {
dialog : : editNumber ( sag : : temperature , sag : : lowtemp , sag : : hightemp , 1 , 0 , XLAT ( " temperature " ) , " " ) ;
} ) ;
dialog : : addSelItem ( XLAT ( " SAG mode " ) , sag : : sagmodes [ sag : : sagmode ] , ' m ' ) ;
dialog : : add_action ( [ ] { sag : : sagmode = sag : : eSagmode ( ( 1 + sag : : sagmode ) % 3 ) ; } ) ;
2022-10-23 13:49:59 +00:00
2024-07-23 19:21:53 +00:00
dialog : : addSelItem ( XLAT ( " min temperature " ) , fts ( sag : : lowtemp ) , ' i ' ) ;
dialog : : add_action ( [ ] {
dialog : : editNumber ( sag : : lowtemp , - 20 , 20 , 1 , 0 , XLAT ( " min temperature " ) , " " ) ;
} ) ;
2022-10-23 13:49:59 +00:00
2024-07-23 19:21:53 +00:00
dialog : : addSelItem ( XLAT ( " max temperature " ) , fts ( sag : : hightemp ) , ' i ' ) ;
dialog : : add_action ( [ ] {
dialog : : editNumber ( sag : : hightemp , - 20 , 20 , 1 , 0 , XLAT ( " high temperature " ) , " " ) ;
} ) ;
2022-08-23 19:48:54 +00:00
2024-07-23 19:21:53 +00:00
dialog : : addSelItem ( XLAT ( " automatic cycle " ) , fts ( sag : : vizsa_len ) , ' c ' ) ;
dialog : : add_action ( [ ] {
dialog : : editNumber ( sag : : vizsa_len , 5 , 1800 , 1 , 0 , XLAT ( " automatic cycle " ) , " " ) ;
} ) ;
2020-03-29 11:41:56 +00:00
2024-07-23 19:21:53 +00:00
dialog : : addBoolItem ( XLAT ( " automatic " ) , sag : : vizsa_start , ' a ' ) ;
dialog : : add_action ( [ ] {
sag : : vizsa_start = sag : : vizsa_start ? 0 : SDL_GetTicks ( ) ;
sag : : sagmode = sagOff ;
} ) ;
2022-08-23 19:48:54 +00:00
2024-07-23 19:21:53 +00:00
dialog : : addBoolItem_action ( XLAT ( " auto-repeat " ) , auto_repeat , ' r ' ) ;
2022-08-23 19:48:54 +00:00
2024-07-23 19:21:53 +00:00
dialog : : addSelItem ( XLAT ( " smoothness " ) , its ( sag_ittime ) , ' s ' ) ;
dialog : : add_action ( [ ] {
dialog : : editNumber ( sag_ittime , 0 , 1000 , 10 , 100 , XLAT ( " smoothness " ) ,
XLAT ( " How much milliseconds to compute before re-rendering the screen when optimizing in the background. Low values look nicer, but may cause less time to be spent on iterations. " )
) ;
} ) ;
2022-08-23 19:48:54 +00:00
2024-07-23 19:21:53 +00:00
dialog : : addBoolItem_action ( XLAT ( " auto-visualize " ) , sag : : auto_visualize , ' b ' ) ;
2022-08-23 19:48:54 +00:00
2024-07-23 19:21:53 +00:00
dialog : : addSelItem ( XLAT ( " SAG method " ) , method_names [ method ] , ' m ' ) ;
dialog : : add_action ( [ ] {
method = eSagMethod ( ( method + 1 ) % method_count ) ;
prepare_method ( ) ;
compute_cost ( ) ;
} ) ;
2022-08-23 19:48:54 +00:00
2024-07-23 19:21:53 +00:00
if ( method = = smMatch ) {
dialog : : addSelItem ( XLAT ( " match parameter A " ) , fts ( match_a ) , ' A ' ) ;
dialog : : add_action ( [ ] {
dialog : : editNumber ( match_a , 0 , 10 , 1 , 1 , XLAT ( " match parameter A " ) , " " ) . reaction = prepare_graph ;
2022-08-23 19:48:54 +00:00
} ) ;
2024-07-23 19:21:53 +00:00
dialog : : addSelItem ( XLAT ( " match parameter B " ) , fts ( match_b ) , ' B ' ) ;
dialog : : add_action ( [ ] {
dialog : : editNumber ( match_b , 0 , 10 , 1 , 1 , XLAT ( " match parameter B " ) , " " ) . reaction = prepare_graph ;
2021-03-30 22:23:01 +00:00
} ) ;
2022-10-23 14:46:21 +00:00
}
2024-07-23 19:21:53 +00:00
if ( method = = smLogistic ) {
dialog : : addSelItem ( XLAT ( " logistic parameter R " ) , fts ( lgsag . R ) , ' A ' ) ;
dialog : : add_action ( [ ] {
dialog : : editNumber ( match_a , 0 , 10 , 1 , 1 , XLAT ( " logistic parameter R " ) , " " ) . reaction = prepare_graph ;
} ) ;
dialog : : addSelItem ( XLAT ( " logistic parameter T " ) , fts ( lgsag . T ) , ' B ' ) ;
dialog : : add_action ( [ ] {
dialog : : editNumber ( match_b , 0 , 10 , 1 , 1 , XLAT ( " logistic parameter T " ) , " " ) . reaction = prepare_graph ;
} ) ;
dialog : : addItem ( XLAT ( " optimize logistic parameters " ) , ' O ' ) ;
dialog : : add_action ( optimize_sag_loglik_logistic ) ;
2022-10-23 14:46:21 +00:00
}
2020-03-29 11:41:56 +00:00
2024-07-23 19:21:53 +00:00
dialog : : addSelItem ( XLAT ( " cost value " ) , fts ( cost ) , ' X ' ) ;
dialog : : add_action ( [ ] {
optimize_sag_loglik_auto ( ) ;
} ) ;
2022-10-23 14:46:21 +00:00
2024-07-23 21:13:25 +00:00
dialog : : addBoolItem_action ( XLAT ( " visualize (sub)cells " ) , visualize_subcells_on , ' v ' ) ;
2024-07-23 19:21:53 +00:00
dialog : : display ( ) ;
}
2022-10-23 14:46:21 +00:00
2024-07-23 19:21:53 +00:00
void auto_orth ( bool set_colors ) {
hyperpoint pmin = C0 , pmax = C0 ;
shiftmatrix M = ggmatrix ( centerover ) ;
ld maxsize = 0 ;
println ( hlog , " cellpoints = " , isize ( cellpoint ) , " sagsubcell_point = " , isize ( sagsubcell_point ) , " M = " , M ) ;
println ( hlog , " NLP = " , NLP ) ;
vector < int > on_cell ( isize ( sagcells ) , 0 ) ;
for ( auto v : sagid ) on_cell [ v ] + + ;
int id = 0 ;
for ( auto p : sagsubcell_point ) {
hyperpoint ret ;
applymodel ( M * p , ret ) ;
println ( hlog , kz ( M * p ) , " -> " , kz ( ret ) ) ;
for ( int i = 0 ; i < 3 ; i + + ) {
if ( ret [ i ] < pmin [ i ] ) pmin [ i ] = ret [ i ] ;
if ( ret [ i ] > pmax [ i ] ) pmax [ i ] = ret [ i ] ;
}
ld size = hypot ( hypot ( ret [ 0 ] , ret [ 1 ] ) , ret [ 2 ] ) ;
if ( size > maxsize & & on_cell [ id ] ) maxsize = size ;
id + + ;
}
println ( hlog , " pmin = " , pmin , " pmax = " , pmax , " maxsize = " , maxsize ) ;
pconf . scale = 0.95 / maxsize ;
pconf . clip_min = - maxsize * 3 - 0.1 ;
pconf . clip_max = maxsize + 0.1 ;
println ( hlog , isize ( vdata ) , " vs " , isize ( sagsubcell_point ) ) ;
if ( set_colors ) for ( int i = 0 ; i < isize ( vdata ) ; i + + ) {
auto p = sagsubcell_point [ sagid [ i ] ] ;
hyperpoint ret ;
applymodel ( M * p , ret ) ;
auto & col = vdata [ i ] . cp . color1 ;
for ( int j = 0 ; j < 3 ; j + + ) {
println ( hlog , " coloring " , tie ( i , j ) , ret [ j ] , " -> " , ilerp ( pmin [ j ] , pmax [ j ] , ret [ j ] ) , " -> " , lerp ( 0 , 255 , ilerp ( pmin [ j ] , pmax [ j ] , ret [ j ] ) ) ) ;
part ( col , j + 1 ) = lerp ( 0 , 255 , ilerp ( pmin [ j ] , pmax [ j ] , ret [ j ] ) ) ;
}
vdata [ i ] . cp . color2 = col ;
2020-03-29 11:41:56 +00:00
}
2022-08-23 19:48:54 +00:00
}
2024-07-23 19:21:53 +00:00
bool use_cells_to_draw ;
set < cell * > cells_to_draw ;
void autoviz ( ) {
no_find_player = true ;
smooth_scrolling = true ;
bobbing = false ;
View = Id ; NLP = Id ; vid . fixed_yz = false ;
models : : configure ( ) ;
make_actual_view ( ) ;
drawthemap ( ) ;
if ( GDIM = = 3 ) game_keys_scroll = true ;
if ( sphere & & GDIM = = 3 ) {
pmodel = mdEquidistant ;
pconf . scale = 0.95 ;
}
if ( hyperbolic & & GDIM = = 2 ) {
pmodel = mdDisk ;
pconf . alpha = 1 ;
pconf . scale = 0.95 ;
}
if ( hyperbolic & & GDIM = = 3 ) {
pmodel = mdDisk ;
pconf . alpha = 1 ;
pconf . scale = 0.95 ;
}
if ( sol | | nil ) {
pmodel = mdLieOrthogonal ;
nisot : : geodesic_movement = false ;
auto_orth ( false ) ;
}
if ( sl2 ) {
pmodel = mdHorocyclic ;
auto_orth ( false ) ;
}
if ( gproduct ) {
pmodel = mdEquidistant ;
NLP = cspin ( 1 , 2 , 75. _deg ) ;
auto_orth ( false ) ;
}
if ( euclid ) {
pmodel = mdDisk ;
pconf . alpha = 1 ;
auto_orth ( false ) ;
}
if ( quotient ) {
if ( GDIM = = 3 ) {
pmodel = mdPerspective ;
if ( hyperbolic ) pmodel = mdDisk ;
frustum_culling = false ;
if ( euclid ) camera_speed * = 10 ;
}
return ;
}
cells_to_draw . clear ( ) ;
for ( auto p : sagcells ) cells_to_draw . insert ( p . first ) ;
rv_hook ( hooks_do_draw , 100 , [ ] ( cell * c , const shiftmatrix & V ) { if ( ! use_cells_to_draw ) return 0 ; return cells_to_draw . count ( c ) ? 1 : - 1 ; } ) ;
rv_hook ( hooks_o_key , 80 , [ ] ( o_funcs & v ) { v . push_back ( named_functionality ( " switch use_cells_to_draw " , [ ] { use_cells_to_draw = ! use_cells_to_draw ; } ) ) ; } ) ;
2022-10-23 13:49:38 +00:00
}
2024-07-23 19:21:53 +00:00
void viz_longpath ( ) {
2022-08-23 19:48:54 +00:00
int DN = isize ( sagid ) ;
2024-07-23 19:21:53 +00:00
int maxdist = - 1 ;
int get_i = 0 , get_j = 0 , count = 0 ;
for ( int i = 0 ; i < DN ; i + + )
for ( int j = 0 ; j < DN ; j + + ) {
auto d = sagdist [ sagid [ i ] ] [ sagid [ j ] ] ;
if ( S3 > = OINF & & sagdist [ sagid [ i ] ] [ 0 ] > = max_sag_dist / 4 ) continue ;
if ( S3 > = OINF & & sagdist [ sagid [ j ] ] [ 0 ] > = max_sag_dist / 4 ) continue ;
if ( d > maxdist ) {
maxdist = d ;
count = 0 ;
}
if ( d = = maxdist ) {
count + + ; if ( hrand ( count ) = = 0 ) get_i = i , get_j = j ;
}
}
println ( hlog , " max distance between nodes is " , maxdist , " at " , tie ( get_i , get_j ) , " appearing " , count , " times " ) ;
history : : create ( sagcells [ sagid [ get_i ] ] . first , sagcells [ sagid [ get_j ] ] . first , Id ) ;
2022-08-23 19:48:54 +00:00
}
2020-03-29 11:41:56 +00:00
int readArgs ( ) {
# if CAP_COMMANDLINE
using namespace arg ;
if ( 0 ) ;
2024-07-23 19:21:53 +00:00
else if ( argis ( " -sag-autoviz " ) ) {
autoviz ( ) ;
2020-03-29 11:41:56 +00:00
}
2024-07-23 19:21:53 +00:00
else if ( argis ( " -sag-longpath " ) ) {
viz_longpath ( ) ;
2022-10-23 14:46:21 +00:00
}
2022-08-23 19:48:54 +00:00
else if ( argis ( " -sagaviz " ) ) {
PHASE ( 3 ) ;
shift ( ) ; sag : : auto_visualize = argi ( ) ;
}
2022-08-20 14:43:26 +00:00
else if ( argis ( " -sagviz " ) ) {
sag : : vizsa_start = SDL_GetTicks ( ) ;
shift ( ) ; sag : : vizsa_len = argi ( ) ;
}
2022-11-13 14:27:19 +00:00
else if ( argis ( " -sagsmooth " ) ) {
shift ( ) ; sag : : sag_ittime = argi ( ) ;
}
2024-07-23 19:21:53 +00:00
2020-03-29 11:41:56 +00:00
else return 1 ;
# endif
return 0 ;
}
2024-07-23 19:21:53 +00:00
void init ( ) {
2020-03-29 13:37:56 +00:00
2024-07-23 19:21:53 +00:00
if ( state & SS_GENERAL ) return ;
state | = SS_GENERAL ;
2020-03-29 11:41:56 +00:00
2024-07-23 19:21:53 +00:00
rogueviz : : init ( RV_GRAPH | RV_WHICHWEIGHT | RV_AUTO_MAXWEIGHT | RV_HAVE_WEIGHT ) ;
2020-03-29 11:41:56 +00:00
2024-07-23 19:21:53 +00:00
rv_hook ( rogueviz : : hooks_close , 100 , clear ) ;
rv_hook ( shmup : : hooks_turn , 100 , turn ) ;
2024-07-23 21:13:25 +00:00
rv_hook ( hooks_drawcell , 100 , visualize_subcells ) ;
2024-07-23 19:21:53 +00:00
rv_hook ( rogueviz : : hooks_rvmenu , 100 , [ ] {
dialog : : addItem ( " SAG settings " , ' s ' ) ;
dialog : : add_action_push ( menu ) ;
2020-03-29 11:41:56 +00:00
} ) ;
2024-07-23 19:21:53 +00:00
weight_label = " min weight " ;
temperature = 0 ; sagmode = sagOff ;
sag_edge = add_edgetype ( " SAG edge " ) ;
}
2020-03-29 11:41:56 +00:00
2024-07-23 19:21:53 +00:00
void clear ( ) {
sagedges . clear ( ) ;
visualization_active = false ;
neighbors . clear ( ) ;
sagcells . clear ( ) ;
ids . clear ( ) ;
sagsubcell_point . clear ( ) ;
sagsubcell_inv . clear ( ) ;
cell_matrix . clear ( ) ;
cellpoint . clear ( ) ;
sagdist . clear ( ) ;
subcell_points . clear ( ) ;
sag_edge = nullptr ;
state = 0 ;
}
2020-03-29 11:41:56 +00:00
2024-07-23 21:26:05 +00:00
string cname ( ) {
if ( euclid ) return " coord-6.txt " ;
if ( PURE ) return " coord-7.txt " ;
return " coord-67.txt " ;
}
int ah = addHook ( hooks_args , 100 , readArgs ) + addHook ( hooks_clearmemory , 100 , clear )
+ addHook_rvslides ( 120 , [ ] ( string s , vector < tour : : slide > & v ) {
if ( s ! = " data " ) return ;
using namespace pres ;
string sagf = " SAG/ " ;
v . push_back (
slide { sagf + " Roguelikes " , 63 , LEGAL : : UNLIMITED | QUICKGEO ,
" A visualization of roguelikes, based on discussion on /r/reddit. "
" See: http://www.roguetemple.com/z/hyper/reddit.php " ,
roguevizslide ( ' 0 ' , [ ] ( ) {
rogueviz : : dftcolor = 0x282828FF ;
rogueviz : : showlabels = true ;
part ( rogueviz : : default_edgetype . color , 0 ) = 181 ;
rogueviz : : sag : : edgepower = 1 ;
rogueviz : : sag : : edgemul = 1 ;
gmatrix . clear ( ) ;
drawthemap ( ) ;
gmatrix0 = gmatrix ;
slide_backup ( rogueviz : : sag : : legacy , true ) ;
rogueviz : : sag : : read_weighted ( RVPATH " sag/roguelikes/edges.csv " ) ;
rogueviz : : readcolor ( RVPATH " sag/roguelikes/color.csv " ) ;
rogueviz : : sag : : load_sag_solution ( RVPATH " sag/roguelikes/ " + cname ( ) ) ;
} )
}
) ;
v . push_back ( slide { sagf + " Programming languages of GitHub " , 64 , LEGAL : : UNLIMITED | QUICKGEO ,
" A visualization of programming languages. " ,
roguevizslide ( ' 0 ' , [ ] ( ) {
rogueviz : : dftcolor = 0x282828FF ;
rogueviz : : showlabels = true ;
part ( rogueviz : : default_edgetype . color , 0 ) = 128 ;
rogueviz : : sag : : edgepower = .4 ;
rogueviz : : sag : : edgemul = .02 ;
gmatrix . clear ( ) ;
drawthemap ( ) ;
gmatrix0 = gmatrix ;
slide_backup ( rogueviz : : sag : : legacy , true ) ;
rogueviz : : sag : : read_weighted ( RVPATH " sag/lang/edges.csv " ) ;
rogueviz : : readcolor ( RVPATH " sag/lang/color.csv " ) ;
rogueviz : : sag : : load_sag_solution ( RVPATH " sag/lang/ " + cname ( ) ) ;
if ( euclid ) rogueviz : : legend . clear ( ) ;
} )
} ) ;
v . push_back ( slide { sagf + " Boardgames " , 62 , LEGAL : : UNLIMITED | QUICKGEO ,
" A visualization of board games, based on discussions on Reddit. " ,
roguevizslide ( ' 0 ' , [ ] ( ) {
rogueviz : : dftcolor = 0x282828FF ;
rogueviz : : showlabels = true ;
part ( rogueviz : : default_edgetype . color , 0 ) = 157 ;
rogueviz : : sag : : edgepower = 1 ;
rogueviz : : sag : : edgemul = 1 ;
gmatrix . clear ( ) ;
drawthemap ( ) ;
gmatrix0 = gmatrix ;
slide_backup ( rogueviz : : sag : : legacy , true ) ;
rogueviz : : sag : : read_weighted ( RVPATH " sag/boardgames/edges.csv " ) ;
rogueviz : : readcolor ( RVPATH " sag/boardgames/color.csv " ) ;
rogueviz : : sag : : load_sag_solution ( RVPATH " sag/boardgames/ " + cname ( ) ) ;
} )
} ) ;
} ) ;
2020-03-29 11:41:56 +00:00
EX }
}
2024-07-23 19:21:53 +00:00
# include "experiments.cpp"