buildinves commited on
Commit
71a91ad
·
verified ·
1 Parent(s): cd183ea

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -104
app.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import gradio as gr
2
  import pandas as pd
3
  import numpy as np
@@ -151,9 +152,8 @@ class AdvancedGridOptimizer:
151
  colors = self.color_schemes[self.current_scheme]
152
 
153
  x_pos = 0
154
- lot_num = 1
155
-
156
- # Set up main plot with RPM green background
157
  ax1.set_xlim(-5, stage_width + 5)
158
  # Adjust y-limits for rear laneway
159
  if self.md_load_type == 'rear':
@@ -292,43 +292,22 @@ class AdvancedGridOptimizer:
292
  # Add lot information (positioned inside the lot)
293
  lot_center_y = 8 + lot_height / 2 # Center of the lot
294
 
295
- # Lot number at top of lot interior
296
- ax1.text(x_pos + width/2, lot_center_y + lot_height/3, f'L{lot_num}',
297
- ha='center', va='center', fontsize=16, fontweight='bold', color='white')
298
-
299
- # Width in middle
300
  ax1.text(x_pos + width/2, lot_center_y, f'{width:.1f}m',
301
- ha='center', va='center', fontsize=14, fontweight='bold', color='white')
302
-
303
- # Lot type
304
- if int(width) in self.lot_specifications:
305
- spec = self.lot_specifications[int(width)]
306
- elif width in self.lot_specifications:
307
- spec = self.lot_specifications[width]
308
- else:
309
- closest_width = min(self.lot_specifications.keys(),
310
- key=lambda x: abs(x - width))
311
- spec = self.lot_specifications[closest_width]
312
- spec = {**spec, 'type': 'Custom'}
313
 
314
- lot_type_text = spec['type']
315
  if is_corner:
316
- lot_type_text = "CORNER"
317
-
318
- # Add build type for MD
319
- if self.development_mode == 'medium_density' and 'build' in spec:
320
- lot_type_text += f"\n{spec['build']}"
321
-
322
- # Type label at bottom of lot interior
323
- ax1.text(x_pos + width/2, lot_center_y - lot_height/3, lot_type_text,
324
- ha='center', va='center', fontsize=11,
325
- bbox=dict(boxstyle="round,pad=0.3", facecolor='#545D51',
326
- edgecolor='white', alpha=0.9), color='white')
327
 
328
- # Dimension lines
329
- ax1.plot([x_pos, x_pos + width], [12, 12], 'w-', linewidth=1, alpha=0.3)
330
- ax1.plot([x_pos, x_pos], [10, 14], 'w-', linewidth=1, alpha=0.3)
331
- ax1.plot([x_pos + width, x_pos + width], [10, 14], 'w-', linewidth=1, alpha=0.3)
 
332
 
333
  # Add garage indicators for rear loaded
334
  if self.md_load_type == 'rear':
@@ -340,7 +319,6 @@ class AdvancedGridOptimizer:
340
  ax1.add_patch(garage)
341
 
342
  x_pos += width
343
- lot_num += 1
344
 
345
  # Add rear alignment line across all lots
346
  rear_y = 8 + lot_height
@@ -383,12 +361,18 @@ class AdvancedGridOptimizer:
383
  for i in range(len(solution) - 1):
384
  if solution[i][0] <= 10.5 and solution[i+1][0] <= 10.5:
385
  slhc_pairs += 1
 
 
 
 
386
  else:
387
  # MD metrics
388
  narrow_count = sum(1 for w, _ in solution if w <= 6.0)
389
  standard_count = sum(1 for w, _ in solution if 6.0 < w <= 8.0)
390
  wide_count = sum(1 for w, _ in solution if w > 8.0)
391
  slhc_pairs = 0 # Not applicable for MD
 
 
392
 
393
  # Calculate actual total width and variance
394
  total_width = sum(w for w, _ in solution)
@@ -409,9 +393,9 @@ class AdvancedGridOptimizer:
409
  f"🎯 DIVERSITY: {diversity_score:.0%} ({unique_widths} types)",
410
  f"📏 GRID VARIANCE: {variance:+.2f}m",
411
  "",
412
- f"{'Narrow (≤6m)' if self.development_mode == 'medium_density' else 'SLHC (≤10.5m)'}: {narrow_count if self.development_mode == 'medium_density' else slhc_count} lots",
413
  f"{'Standard (6-8m)' if self.development_mode == 'medium_density' else 'Standard (11-14m)'}: {standard_count} lots",
414
- f"{'Wide (>8m)' if self.development_mode == 'medium_density' else 'Premium (>14m)'}: {wide_count if self.development_mode == 'medium_density' else premium_count} lots",
415
  "",
416
  f"{'🚗 Access: ' + ('Rear Laneway' if self.md_load_type == 'rear' else 'Front Loaded') if self.development_mode == 'medium_density' else f'🚗 SLHC Pairs: {slhc_pairs}'}",
417
  yield_text
@@ -513,14 +497,12 @@ class AdvancedGridOptimizer:
513
  best_solution = None
514
  best_fitness = -float('inf')
515
 
516
- # For MD, corners don't need to be wider than internal
517
  if self.development_mode == 'medium_density':
518
  min_internal = min(internal_widths) if internal_widths else 4.5
519
- min_corner_width = base_corner_width - tolerance
520
  else:
521
- # Ensure corners are at least as wide as smallest internal lot
522
  min_internal = min(internal_widths) if internal_widths else 8.5
523
- min_corner_width = max(base_corner_width - tolerance, min_internal)
524
 
525
  # Try variations of corner widths within tolerance
526
  variations = np.arange(min_corner_width,
@@ -538,11 +520,10 @@ class AdvancedGridOptimizer:
538
  internal_solution = self.find_exact_solution_with_diversity(internal_width, internal_widths)
539
 
540
  if internal_solution:
541
- # For conventional, verify no internal lot is wider than corners
542
- if self.development_mode == 'conventional':
543
- max_internal = max(internal_solution) if internal_solution else 0
544
- if max_internal > min(corner1, corner2):
545
- continue
546
 
547
  # Build complete solution
548
  solution = [(round(corner1, 1), 'corner')]
@@ -577,9 +558,10 @@ class AdvancedGridOptimizer:
577
 
578
  # Strategy 2: Try flexible corners if enabled
579
  if allow_custom_corners and standard_internal:
580
- # For MD, try all widths as potential corners
581
  if self.development_mode == 'medium_density':
582
- corner_bases = list(enabled_widths)
 
583
  else:
584
  # For conventional, use traditional corner widths
585
  corner_bases = [11.0, 13.3, 14.8, 16.8, 14.0, 16.0]
@@ -602,15 +584,10 @@ class AdvancedGridOptimizer:
602
 
603
  # Separate widths by size
604
  all_widths = sorted(enabled_widths)
 
605
 
606
- if self.development_mode == 'medium_density':
607
- # For MD, any width can be a corner
608
- corner_options = all_widths
609
- min_internal_width = min(all_widths) if all_widths else 4.5
610
- else:
611
- # For conventional, maintain hierarchy
612
- min_internal_width = min(all_widths)
613
- corner_options = [w for w in enabled_widths if w >= max(11.0, min_internal_width)]
614
 
615
  best_solution = None
616
  best_fitness = -float('inf')
@@ -632,11 +609,10 @@ class AdvancedGridOptimizer:
632
  )
633
 
634
  for internal_widths in internal_solutions:
635
- # For conventional, verify no internal lot is wider than corners
636
- if self.development_mode == 'conventional':
637
- max_internal = max(internal_widths) if internal_widths else 0
638
- if max_internal > min(corner1, corner2):
639
- continue
640
 
641
  # Build complete solution
642
  solution = [(corner1, 'corner')]
@@ -651,25 +627,22 @@ class AdvancedGridOptimizer:
651
  best_fitness = fitness
652
  best_solution = optimized
653
 
654
- # If no good solution, try without strict corner rules
655
  if not best_solution:
656
  all_solutions = []
657
  self.find_all_combinations_recursive(stage_width, sorted(enabled_widths),
658
  [], all_solutions, 20)
659
 
660
  for widths in all_solutions[:50]:
661
- # For MD, just use the solution as-is
662
- if self.development_mode == 'medium_density':
663
- solution = [(w, 'standard') for w in widths]
 
 
 
 
664
  else:
665
- # For conventional, ensure corners are among the largest lots
666
- sorted_widths = sorted(widths)
667
- if len(sorted_widths) >= 2:
668
- solution = [(sorted_widths[-1], 'corner')]
669
- solution.extend([(w, 'standard') for w in sorted_widths[:-2]])
670
- solution.append((sorted_widths[-2], 'corner'))
671
- else:
672
- solution = [(w, 'standard') for w in widths]
673
 
674
  optimized = self.optimize_lot_grouping(solution)
675
  fitness = self.evaluate_solution_with_diversity(optimized, stage_width)
@@ -966,36 +939,40 @@ class AdvancedGridOptimizer:
966
  fitness -= max_repetition * 500 # Penalty for too many of same width
967
  fitness += diversity_ratio * 3000 # Bonus for good diversity ratio
968
 
969
- # Mode-specific evaluation
970
- if self.development_mode == 'conventional':
971
- # Corner evaluation for conventional
972
- if len(solution) >= 2:
973
- first_width = solution[0][0]
974
- last_width = solution[-1][0]
975
-
976
- # Penalty for SLHC on corners
977
- if first_width <= 10.5:
978
- fitness -= 2000
979
- if last_width <= 10.5:
980
- fitness -= 2000
981
-
982
- # Bonus for good corners
983
- if first_width >= 11.0:
984
- fitness += 1000
985
- if last_width >= 11.0:
986
- fitness += 1000
987
-
988
- # Balance bonus
989
- corner_diff = abs(first_width - last_width)
990
- if corner_diff < 0.1:
991
- fitness += 1500 # Perfect match
992
- elif corner_diff <= 1.0:
993
- fitness += 1000 # Very good
994
- elif corner_diff <= 2.0:
995
- fitness += 500 # Good
996
- else:
997
- fitness -= 500 # Poor balance
998
 
 
 
 
 
 
 
 
 
 
 
 
 
 
999
  # SLHC grouping bonus
1000
  for i in range(len(solution) - 1):
1001
  if solution[i][0] <= 10.5 and solution[i+1][0] <= 10.5:
 
1
+
2
  import gradio as gr
3
  import pandas as pd
4
  import numpy as np
 
152
  colors = self.color_schemes[self.current_scheme]
153
 
154
  x_pos = 0
155
+ for i, (width, lot_type) in enumerate(solution):
156
+ # Get base color
 
157
  ax1.set_xlim(-5, stage_width + 5)
158
  # Adjust y-limits for rear laneway
159
  if self.md_load_type == 'rear':
 
292
  # Add lot information (positioned inside the lot)
293
  lot_center_y = 8 + lot_height / 2 # Center of the lot
294
 
295
+ # Just show width in center (like conventional)
 
 
 
 
296
  ax1.text(x_pos + width/2, lot_center_y, f'{width:.1f}m',
297
+ ha='center', va='center', fontsize=16, fontweight='bold', color='white')
 
 
 
 
 
 
 
 
 
 
 
298
 
299
+ # Only show CORNER label for corner lots - positioned lower
300
  if is_corner:
301
+ ax1.text(x_pos + width/2, 8 + lot_height/4, "CORNER",
302
+ ha='center', va='center', fontsize=12,
303
+ bbox=dict(boxstyle="round,pad=0.3", facecolor='#545D51',
304
+ edgecolor='white', alpha=0.9, linewidth=1.5), color='white')
 
 
 
 
 
 
 
305
 
306
+ # Dimension lines - make more visible
307
+ dim_y = 8 + lot_height + 2 # Just above the lot
308
+ ax1.plot([x_pos, x_pos + width], [dim_y, dim_y], 'w-', linewidth=1.5, alpha=0.6)
309
+ ax1.plot([x_pos, x_pos], [dim_y - 1, dim_y + 1], 'w-', linewidth=1.5, alpha=0.6)
310
+ ax1.plot([x_pos + width, x_pos + width], [dim_y - 1, dim_y + 1], 'w-', linewidth=1.5, alpha=0.6)
311
 
312
  # Add garage indicators for rear loaded
313
  if self.md_load_type == 'rear':
 
319
  ax1.add_patch(garage)
320
 
321
  x_pos += width
 
322
 
323
  # Add rear alignment line across all lots
324
  rear_y = 8 + lot_height
 
361
  for i in range(len(solution) - 1):
362
  if solution[i][0] <= 10.5 and solution[i+1][0] <= 10.5:
363
  slhc_pairs += 1
364
+
365
+ # Set MD-specific variables to avoid reference errors
366
+ narrow_count = slhc_count
367
+ wide_count = premium_count
368
  else:
369
  # MD metrics
370
  narrow_count = sum(1 for w, _ in solution if w <= 6.0)
371
  standard_count = sum(1 for w, _ in solution if 6.0 < w <= 8.0)
372
  wide_count = sum(1 for w, _ in solution if w > 8.0)
373
  slhc_pairs = 0 # Not applicable for MD
374
+ slhc_count = narrow_count
375
+ premium_count = wide_count
376
 
377
  # Calculate actual total width and variance
378
  total_width = sum(w for w, _ in solution)
 
393
  f"🎯 DIVERSITY: {diversity_score:.0%} ({unique_widths} types)",
394
  f"📏 GRID VARIANCE: {variance:+.2f}m",
395
  "",
396
+ f"{'Narrow (≤6m)' if self.development_mode == 'medium_density' else 'SLHC (≤10.5m)'}: {narrow_count} lots",
397
  f"{'Standard (6-8m)' if self.development_mode == 'medium_density' else 'Standard (11-14m)'}: {standard_count} lots",
398
+ f"{'Wide (>8m)' if self.development_mode == 'medium_density' else 'Premium (>14m)'}: {wide_count} lots",
399
  "",
400
  f"{'🚗 Access: ' + ('Rear Laneway' if self.md_load_type == 'rear' else 'Front Loaded') if self.development_mode == 'medium_density' else f'🚗 SLHC Pairs: {slhc_pairs}'}",
401
  yield_text
 
497
  best_solution = None
498
  best_fitness = -float('inf')
499
 
500
+ # Ensure corners are at least as wide as smallest internal lot
501
  if self.development_mode == 'medium_density':
502
  min_internal = min(internal_widths) if internal_widths else 4.5
 
503
  else:
 
504
  min_internal = min(internal_widths) if internal_widths else 8.5
505
+ min_corner_width = max(base_corner_width - tolerance, min_internal)
506
 
507
  # Try variations of corner widths within tolerance
508
  variations = np.arange(min_corner_width,
 
520
  internal_solution = self.find_exact_solution_with_diversity(internal_width, internal_widths)
521
 
522
  if internal_solution:
523
+ # Verify no internal lot is wider than corners
524
+ max_internal = max(internal_solution) if internal_solution else 0
525
+ if max_internal > min(corner1, corner2):
526
+ continue
 
527
 
528
  # Build complete solution
529
  solution = [(round(corner1, 1), 'corner')]
 
558
 
559
  # Strategy 2: Try flexible corners if enabled
560
  if allow_custom_corners and standard_internal:
561
+ # Use appropriate corner bases for each mode
562
  if self.development_mode == 'medium_density':
563
+ # For MD, use the largest available widths as corner bases
564
+ corner_bases = sorted(enabled_widths, reverse=True)[:4]
565
  else:
566
  # For conventional, use traditional corner widths
567
  corner_bases = [11.0, 13.3, 14.8, 16.8, 14.0, 16.0]
 
584
 
585
  # Separate widths by size
586
  all_widths = sorted(enabled_widths)
587
+ min_internal_width = min(all_widths) if all_widths else 4.5
588
 
589
+ # Corner lots must be at least as wide as smallest internal lot
590
+ corner_options = [w for w in enabled_widths if w >= max(11.0 if self.development_mode == 'conventional' else min_internal_width, min_internal_width)]
 
 
 
 
 
 
591
 
592
  best_solution = None
593
  best_fitness = -float('inf')
 
609
  )
610
 
611
  for internal_widths in internal_solutions:
612
+ # Verify no internal lot is wider than corners
613
+ max_internal = max(internal_widths) if internal_widths else 0
614
+ if max_internal > min(corner1, corner2):
615
+ continue # Skip if internal lots are wider than corners
 
616
 
617
  # Build complete solution
618
  solution = [(corner1, 'corner')]
 
627
  best_fitness = fitness
628
  best_solution = optimized
629
 
630
+ # If no good solution, try without strict corner rules but maintain size hierarchy
631
  if not best_solution:
632
  all_solutions = []
633
  self.find_all_combinations_recursive(stage_width, sorted(enabled_widths),
634
  [], all_solutions, 20)
635
 
636
  for widths in all_solutions[:50]:
637
+ # Ensure corners are among the largest lots
638
+ sorted_widths = sorted(widths)
639
+ if len(sorted_widths) >= 2:
640
+ # Put two largest widths at corners
641
+ solution = [(sorted_widths[-1], 'corner')] # Largest
642
+ solution.extend([(w, 'standard') for w in sorted_widths[:-2]])
643
+ solution.append((sorted_widths[-2], 'corner')) # Second largest
644
  else:
645
+ solution = [(w, 'standard') for w in widths]
 
 
 
 
 
 
 
646
 
647
  optimized = self.optimize_lot_grouping(solution)
648
  fitness = self.evaluate_solution_with_diversity(optimized, stage_width)
 
939
  fitness -= max_repetition * 500 # Penalty for too many of same width
940
  fitness += diversity_ratio * 3000 # Bonus for good diversity ratio
941
 
942
+ # Corner evaluation - apply to both conventional and MD
943
+ if len(solution) >= 2:
944
+ first_width = solution[0][0]
945
+ last_width = solution[-1][0]
946
+
947
+ # Get max internal width
948
+ internal_widths = [w for w, t in solution[1:-1]]
949
+ max_internal = max(internal_widths) if internal_widths else 0
950
+
951
+ # Penalty if corners are not wider than internals
952
+ if first_width <= max_internal:
953
+ fitness -= 2000
954
+ if last_width <= max_internal:
955
+ fitness -= 2000
956
+
957
+ # Bonus for good corners (wider than internals)
958
+ if first_width > max_internal:
959
+ fitness += 1000
960
+ if last_width > max_internal:
961
+ fitness += 1000
 
 
 
 
 
 
 
 
 
962
 
963
+ # Balance bonus
964
+ corner_diff = abs(first_width - last_width)
965
+ if corner_diff < 0.1:
966
+ fitness += 1500 # Perfect match
967
+ elif corner_diff <= 1.0:
968
+ fitness += 1000 # Very good
969
+ elif corner_diff <= 2.0:
970
+ fitness += 500 # Good
971
+ else:
972
+ fitness -= 500 # Poor balance
973
+
974
+ # Mode-specific bonuses
975
+ if self.development_mode == 'conventional':
976
  # SLHC grouping bonus
977
  for i in range(len(solution) - 1):
978
  if solution[i][0] <= 10.5 and solution[i+1][0] <= 10.5: